diff options
author | Frediano Ziglio <fziglio@redhat.com> | 2016-09-22 16:40:55 +0100 |
---|---|---|
committer | Jonathon Jongsma <jjongsma@redhat.com> | 2016-10-07 14:46:37 -0500 |
commit | 5193360594d461a015d43e7b7ca6ed51e8481035 (patch) | |
tree | 742749361ee97c1bcb372319a8a9f5997a24a4f8 | |
parent | 32aa710d22ecf0a20cae27e728c927fcf4984c9f (diff) |
Convert RedChannelClient hierarchy to GObject
Convert the RedChannelClient heirarchy into GObjects. Since the existing
constructors could fail and return NULL, I inherited the base channel
client from GInitable, which introduces a dependency on gio.
When using private structs with GObject, there's a maximum size of (I
think) 64k, which was exceeded by some of the private structs. To avoid
this limitation I changed some members to dynamically allocated.
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | server/Makefile.am | 2 | ||||
-rw-r--r-- | server/cursor-channel-client.c | 67 | ||||
-rw-r--r-- | server/cursor-channel-client.h | 39 | ||||
-rw-r--r-- | server/dcc-private.h | 8 | ||||
-rw-r--r-- | server/dcc.c | 195 | ||||
-rw-r--r-- | server/dcc.h | 42 | ||||
-rw-r--r-- | server/display-channel.c | 4 | ||||
-rw-r--r-- | server/dummy-channel-client.c | 158 | ||||
-rw-r--r-- | server/dummy-channel-client.h | 64 | ||||
-rw-r--r-- | server/inputs-channel-client.c | 58 | ||||
-rw-r--r-- | server/inputs-channel-client.h | 51 | ||||
-rw-r--r-- | server/main-channel-client.c | 139 | ||||
-rw-r--r-- | server/main-channel-client.h | 39 | ||||
-rw-r--r-- | server/red-channel-client-private.h | 4 | ||||
-rw-r--r-- | server/red-channel-client.c | 561 | ||||
-rw-r--r-- | server/red-channel-client.h | 85 | ||||
-rw-r--r-- | server/red-channel.h | 31 | ||||
-rw-r--r-- | server/smartcard-channel-client.c | 118 | ||||
-rw-r--r-- | server/smartcard-channel-client.h | 47 | ||||
-rw-r--r-- | server/smartcard.c | 16 | ||||
-rw-r--r-- | server/sound.c | 9 | ||||
-rw-r--r-- | server/spice-server.h | 16 | ||||
-rw-r--r-- | server/spicevmc.c | 6 |
24 files changed, 1376 insertions, 387 deletions
diff --git a/configure.ac b/configure.ac index f8284f63..483f18bc 100644 --- a/configure.ac +++ b/configure.ac @@ -147,8 +147,8 @@ SPICE_PROTOCOL_MIN_VER=0.12.12 PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER]) AC_SUBST([SPICE_PROTOCOL_MIN_VER]) -PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.22]) -AS_VAR_APPEND([SPICE_REQUIRES], [" glib-2.0 >= 2.22"]) +PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.22 gio-2.0 >= 2.22]) +AS_VAR_APPEND([SPICE_REQUIRES], [" glib-2.0 >= 2.22 gio-2.0 >= 2.22"]) PKG_CHECK_MODULES([GOBJECT2], [gobject-2.0 >= 2.22]) AS_VAR_APPEND([SPICE_REQUIRES], [" gobject-2.0 >= 2.22"]) diff --git a/server/Makefile.am b/server/Makefile.am index abbec167..f217399b 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -100,6 +100,8 @@ libserver_la_SOURCES = \ red-channel-client.c \ red-channel-client.h \ red-channel-client-private.h \ + dummy-channel-client.c \ + dummy-channel-client.h \ red-common.h \ dispatcher.c \ dispatcher.h \ diff --git a/server/cursor-channel-client.c b/server/cursor-channel-client.c index 89c23a34..25082d7d 100644 --- a/server/cursor-channel-client.c +++ b/server/cursor-channel-client.c @@ -40,7 +40,11 @@ enum { RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE, }; -typedef struct CursorChannelClientPrivate CursorChannelClientPrivate; +G_DEFINE_TYPE(CursorChannelClient, cursor_channel_client, RED_TYPE_CHANNEL_CLIENT) + +#define CURSOR_CHANNEL_CLIENT_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_CURSOR_CHANNEL_CLIENT, CursorChannelClientPrivate)) + struct CursorChannelClientPrivate { RedCacheItem *cursor_cache[CURSOR_CACHE_HASH_SIZE]; @@ -49,12 +53,19 @@ struct CursorChannelClientPrivate uint32_t cursor_cache_items; }; -struct CursorChannelClient +static void +cursor_channel_client_class_init(CursorChannelClientClass *klass) { - RedChannelClient base; + g_type_class_add_private(klass, sizeof(CursorChannelClientPrivate)); +} - CursorChannelClientPrivate priv[1]; -}; +static void +cursor_channel_client_init(CursorChannelClient *self) +{ + self->priv = CURSOR_CHANNEL_CLIENT_PRIVATE(self); + ring_init(&self->priv->cursor_cache_lru); + self->priv->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE; +} #define CLIENT_CURSOR_CACHE #include "cache-item.tmpl.c" @@ -90,28 +101,36 @@ CursorChannelClient* cursor_channel_client_new(CursorChannel *cursor, RedClient uint32_t *common_caps, int num_common_caps, uint32_t *caps, int num_caps) { - spice_return_val_if_fail(cursor, NULL); - spice_return_val_if_fail(client, NULL); - spice_return_val_if_fail(stream, NULL); - spice_return_val_if_fail(!num_common_caps || common_caps, NULL); - spice_return_val_if_fail(!num_caps || caps, NULL); - - CursorChannelClient *ccc = - CURSOR_CHANNEL_CLIENT(red_channel_client_create(sizeof(CursorChannelClient), - RED_CHANNEL(cursor), - client, stream, - FALSE, - num_common_caps, - common_caps, - num_caps, - caps)); - spice_return_val_if_fail(ccc != NULL, NULL); + CursorChannelClient *rcc; + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } + + rcc = g_initable_new(TYPE_CURSOR_CHANNEL_CLIENT, + NULL, NULL, + "channel", cursor, + "client", client, + "stream", stream, + "monitor-latency", FALSE, + "common-caps", common_caps_array, + "caps", caps_array, + NULL); COMMON_GRAPHICS_CHANNEL(cursor)->during_target_migrate = mig_target; - ring_init(&ccc->priv->cursor_cache_lru); - ccc->priv->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE; + if (caps_array) + g_array_unref(caps_array); + if (common_caps_array) + g_array_unref(common_caps_array); - return ccc; + return rcc; } RedCacheItem* cursor_channel_client_cache_find(CursorChannelClient *ccc, uint64_t id) diff --git a/server/cursor-channel-client.h b/server/cursor-channel-client.h index 278005cb..2336b95e 100644 --- a/server/cursor-channel-client.h +++ b/server/cursor-channel-client.h @@ -18,15 +18,46 @@ #ifndef CURSOR_CHANNEL_CLIENT_H_ # define CURSOR_CHANNEL_CLIENT_H_ +#include <glib-object.h> + #include "cache-item.h" #include "red-common.h" -#include "red-channel.h" +#include "red-channel-client.h" #include "reds-stream.h" -typedef struct CursorChannel CursorChannel; +G_BEGIN_DECLS + +#define TYPE_CURSOR_CHANNEL_CLIENT cursor_channel_client_get_type() + +#define CURSOR_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_CURSOR_CHANNEL_CLIENT, CursorChannelClient)) +#define CURSOR_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_CURSOR_CHANNEL_CLIENT, CursorChannelClientClass)) +#define IS_CURSOR_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_CURSOR_CHANNEL_CLIENT)) +#define IS_CURSOR_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_CURSOR_CHANNEL_CLIENT)) +#define CURSOR_CHANNEL_CLIENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_CURSOR_CHANNEL_CLIENT, CursorChannelClientClass)) + typedef struct CursorChannelClient CursorChannelClient; +typedef struct CursorChannelClientClass CursorChannelClientClass; +typedef struct CursorChannelClientPrivate CursorChannelClientPrivate; +typedef struct CursorChannel CursorChannel; + +struct CursorChannelClient +{ + RedChannelClient parent; + + CursorChannelClientPrivate *priv; +}; -#define CURSOR_CHANNEL_CLIENT(Client) ((CursorChannelClient*)(Client)) +struct CursorChannelClientClass +{ + RedChannelClientClass parent_class; +}; + +GType cursor_channel_client_get_type(void) G_GNUC_CONST; CursorChannelClient* cursor_channel_client_new(CursorChannel *cursor, RedClient *client, @@ -41,4 +72,6 @@ void cursor_channel_client_on_disconnect(RedChannelClient *rcc); RedCacheItem* cursor_channel_client_cache_find(CursorChannelClient *ccc, uint64_t id); int cursor_channel_client_cache_add(CursorChannelClient *ccc, uint64_t id, size_t size); +G_END_DECLS + #endif /* CURSOR_CHANNEL_CLIENT_H_ */ diff --git a/server/dcc-private.h b/server/dcc-private.h index 46f1db34..de6ea92a 100644 --- a/server/dcc-private.h +++ b/server/dcc-private.h @@ -61,12 +61,4 @@ struct DisplayChannelClientPrivate bool gl_draw_ongoing; }; -struct DisplayChannelClient -{ - RedChannelClient base; - int is_low_bandwidth; - - DisplayChannelClientPrivate priv[1]; -}; - #endif /* DCC_PRIVATE_H_ */ diff --git a/server/dcc.c b/server/dcc.c index ce8677d3..3ded1b9b 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -22,8 +22,150 @@ #include "dcc-private.h" #include "display-channel.h" #include "red-channel-client-private.h" +#include "spice-server-enums.h" + +G_DEFINE_TYPE(DisplayChannelClient, display_channel_client, RED_TYPE_CHANNEL_CLIENT) #define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano +#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128 + +enum +{ + PROP0, + PROP_IMAGE_COMPRESSION, + PROP_JPEG_STATE, + PROP_ZLIB_GLZ_STATE +}; + +static void +display_channel_client_get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + DisplayChannelClient *self = DISPLAY_CHANNEL_CLIENT(object); + + switch (property_id) + { + case PROP_IMAGE_COMPRESSION: + g_value_set_enum(value, self->priv->image_compression); + break; + case PROP_JPEG_STATE: + g_value_set_enum(value, self->priv->jpeg_state); + break; + case PROP_ZLIB_GLZ_STATE: + g_value_set_enum(value, self->priv->zlib_glz_state); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void +display_channel_client_set_property(GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + DisplayChannelClient *self = DISPLAY_CHANNEL_CLIENT(object); + + switch (property_id) + { + case PROP_IMAGE_COMPRESSION: + self->priv->image_compression = g_value_get_enum(value); + break; + case PROP_JPEG_STATE: + self->priv->jpeg_state = g_value_get_enum(value); + break; + case PROP_ZLIB_GLZ_STATE: + self->priv->zlib_glz_state = g_value_get_enum(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void dcc_init_stream_agents(DisplayChannelClient *dcc); + +static void +display_channel_client_constructed(GObject *object) +{ + DisplayChannelClient *self = DISPLAY_CHANNEL_CLIENT(object); + + G_OBJECT_CLASS(display_channel_client_parent_class)->constructed(object); + + dcc_init_stream_agents(self); + + image_encoders_init(&self->priv->encoders, &DCC_TO_DC(self)->priv->encoder_shared_data); +} + +static void +display_channel_client_finalize(GObject *object) +{ + DisplayChannelClient *self = DISPLAY_CHANNEL_CLIENT(object); + g_free(self->priv); + + G_OBJECT_CLASS(display_channel_client_parent_class)->finalize(object); +} + +static void +display_channel_client_class_init(DisplayChannelClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->get_property = display_channel_client_get_property; + object_class->set_property = display_channel_client_set_property; + object_class->constructed = display_channel_client_constructed; + object_class->finalize = display_channel_client_finalize; + + g_object_class_install_property(object_class, + PROP_IMAGE_COMPRESSION, + g_param_spec_enum("image-compression", + "image compression", + "Image compression type", + SPICE_TYPE_SPICE_IMAGE_COMPRESSION_T, + SPICE_IMAGE_COMPRESSION_INVALID, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property(object_class, + PROP_JPEG_STATE, + g_param_spec_enum("jpeg-state", + "jpeg state", + "JPEG compression state", + SPICE_TYPE_SPICE_WAN_COMPRESSION_T, + SPICE_WAN_COMPRESSION_INVALID, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property(object_class, + PROP_ZLIB_GLZ_STATE, + g_param_spec_enum("zlib-glz-state", + "zlib glz state", + "zlib glz state", + SPICE_TYPE_SPICE_WAN_COMPRESSION_T, + SPICE_WAN_COMPRESSION_INVALID, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +static void display_channel_client_init(DisplayChannelClient *self) +{ + /* we need to allocate the private data manually here since + * g_type_class_add_private() doesn't support private structs larger than + * 64k */ + self->priv = g_new0(DisplayChannelClientPrivate, 1); + + ring_init(&self->priv->palette_cache_lru); + self->priv->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE; + // todo: tune quality according to bandwidth + self->priv->encoders.jpeg_quality = 85; + + self->priv->send_data.free_list.res = + spice_malloc(sizeof(SpiceResourceList) + + DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID)); + self->priv->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE; +} static RedSurfaceCreateItem *red_surface_create_item_new(RedChannel* channel, uint32_t surface_id, @@ -336,8 +478,6 @@ static void dcc_init_stream_agents(DisplayChannelClient *dcc) red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT); } -#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128 - DisplayChannelClient *dcc_new(DisplayChannel *display, RedClient *client, RedsStream *stream, int mig_target, @@ -349,35 +489,38 @@ DisplayChannelClient *dcc_new(DisplayChannel *display, { DisplayChannelClient *dcc; + GArray *common_caps_array = NULL, *caps_array = NULL; - dcc = DISPLAY_CHANNEL_CLIENT(red_channel_client_create( - sizeof(DisplayChannelClient), - &COMMON_GRAPHICS_CHANNEL(display)->base, - client, stream, TRUE, - num_common_caps, common_caps, - num_caps, caps)); + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } + dcc = g_initable_new(TYPE_DISPLAY_CHANNEL_CLIENT, + NULL, NULL, + "channel", display, + "client", client, + "stream", stream, + "monitor-latency", TRUE, + "common-caps", common_caps_array, + "caps", caps_array, + "image-compression", image_compression, + "jpeg-state", jpeg_state, + "zlib-glz-state", zlib_glz_state, + NULL); + spice_info("New display (client %p) dcc %p stream %p", client, dcc, stream); display->common.during_target_migrate = mig_target; dcc->priv->id = display->common.qxl->id; - spice_return_val_if_fail(dcc, NULL); - spice_info("New display (client %p) dcc %p stream %p", client, dcc, stream); - - ring_init(&dcc->priv->palette_cache_lru); - dcc->priv->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE; - dcc->priv->image_compression = image_compression; - dcc->priv->jpeg_state = jpeg_state; - dcc->priv->zlib_glz_state = zlib_glz_state; - // TODO: tune quality according to bandwidth - dcc->priv->encoders.jpeg_quality = 85; - - dcc->priv->send_data.free_list.res = - spice_malloc(sizeof(SpiceResourceList) + - DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID)); - dcc->priv->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE; - - dcc_init_stream_agents(dcc); - image_encoders_init(&dcc->priv->encoders, &display->priv->encoder_shared_data); + if (common_caps_array) + g_array_unref(common_caps_array); + if (caps_array) + g_array_unref(caps_array); return dcc; } diff --git a/server/dcc.h b/server/dcc.h index 932e0512..2456f09f 100644 --- a/server/dcc.h +++ b/server/dcc.h @@ -18,12 +18,49 @@ #ifndef DCC_H_ # define DCC_H_ +#include <glib-object.h> + #include "image-encoders.h" #include "image-cache.h" #include "pixmap-cache.h" #include "red-worker.h" #include "display-limits.h" +G_BEGIN_DECLS + +#define TYPE_DISPLAY_CHANNEL_CLIENT display_channel_client_get_type() + +#define DISPLAY_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DISPLAY_CHANNEL_CLIENT, DisplayChannelClient)) +#define DISPLAY_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DISPLAY_CHANNEL_CLIENT, DisplayChannelClientClass)) +#define IS_DISPLAY_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_DISPLAY_CHANNEL_CLIENT)) +#define IS_DISPLAY_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DISPLAY_CHANNEL_CLIENT)) +#define DISPLAY_CHANNEL_CLIENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DISPLAY_CHANNEL_CLIENT, DisplayChannelClientClass)) + +typedef struct DisplayChannelClient DisplayChannelClient; +typedef struct DisplayChannelClientClass DisplayChannelClientClass; +typedef struct DisplayChannelClientPrivate DisplayChannelClientPrivate; + +struct DisplayChannelClient +{ + RedChannelClient parent; + + int is_low_bandwidth; + + DisplayChannelClientPrivate *priv; +}; + +struct DisplayChannelClientClass +{ + RedChannelClientClass parent_class; +}; + +GType display_channel_client_get_type(void) G_GNUC_CONST; + #define PALETTE_CACHE_HASH_SHIFT 8 #define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT) #define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1) @@ -57,10 +94,7 @@ typedef struct FreeList { WaitForChannels wait; } FreeList; -typedef struct DisplayChannelClient DisplayChannelClient; - #define DCC_TO_DC(dcc) ((DisplayChannel*)red_channel_client_get_channel((RedChannelClient*)dcc)) -#define DISPLAY_CHANNEL_CLIENT(rcc) ((DisplayChannelClient*)rcc) typedef struct RedSurfaceCreateItem { RedPipeItem pipe_item; @@ -172,4 +206,6 @@ void dcc_set_max_stream_bit_rate(DisplayChannelClient *dcc, uint64_t rate); int dcc_config_socket(RedChannelClient *rcc); gboolean dcc_is_low_bandwidth(DisplayChannelClient *dcc); +G_END_DECLS + #endif /* DCC_H_ */ diff --git a/server/display-channel.c b/server/display-channel.c index 32f8e671..b9366b5b 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -1128,7 +1128,7 @@ int display_channel_wait_for_migrate_data(DisplayChannel *display) rcc = g_list_nth_data(channel->clients, 0); - red_channel_client_ref(rcc); + g_object_ref(rcc); for (;;) { red_channel_client_receive(rcc); if (!red_channel_client_is_connected(rcc)) { @@ -1146,7 +1146,7 @@ int display_channel_wait_for_migrate_data(DisplayChannel *display) } usleep(DISPLAY_CLIENT_RETRY_INTERVAL); } - red_channel_client_unref(rcc); + g_object_unref(rcc); return ret; } diff --git a/server/dummy-channel-client.c b/server/dummy-channel-client.c new file mode 100644 index 00000000..1b72137a --- /dev/null +++ b/server/dummy-channel-client.c @@ -0,0 +1,158 @@ +/* + 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/>. +*/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "dummy-channel-client.h" +#include "red-channel.h" + +static void dummy_channel_client_initable_interface_init(GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE(DummyChannelClient, dummy_channel_client, RED_TYPE_CHANNEL_CLIENT, + G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, + dummy_channel_client_initable_interface_init)) + +#define DUMMY_CHANNEL_CLIENT_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_DUMMY_CHANNEL_CLIENT, DummyChannelClientPrivate)) + +struct DummyChannelClientPrivate +{ + gboolean connected; +}; + +static int dummy_channel_client_pre_create_validate(RedChannel *channel, RedClient *client) +{ + if (red_client_get_channel(client, channel->type, channel->id)) { + spice_printerr("Error client %p: duplicate channel type %d id %d", + client, channel->type, channel->id); + return FALSE; + } + return TRUE; +} + +static gboolean dummy_channel_client_initable_init(GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + GError *local_error = NULL; + DummyChannelClient *self = DUMMY_CHANNEL_CLIENT(initable); + RedChannelClient *rcc = RED_CHANNEL_CLIENT(self); + RedClient *client = red_channel_client_get_client(rcc); + RedChannel *channel = red_channel_client_get_channel(rcc); + pthread_mutex_lock(&client->lock); + if (!dummy_channel_client_pre_create_validate(channel, + client)) { + g_set_error(&local_error, + SPICE_SERVER_ERROR, + SPICE_SERVER_ERROR_FAILED, + "Client %p: duplicate channel type %d id %d", + client, channel->type, channel->id); + goto cleanup; + } + + rcc->incoming.header.data = rcc->incoming.header_buf; + + red_channel_add_client(channel, rcc); + red_client_add_channel(client, rcc); + +cleanup: + pthread_mutex_unlock(&client->lock); + if (local_error) { + g_warning("Failed to create channel client: %s", local_error->message); + g_propagate_error(error, local_error); + } + return local_error == NULL; +} + +static void dummy_channel_client_initable_interface_init(GInitableIface *iface) +{ + iface->init = dummy_channel_client_initable_init; +} + +static gboolean dummy_channel_client_is_connected(RedChannelClient *rcc) +{ + return DUMMY_CHANNEL_CLIENT(rcc)->priv->connected; +} + +static void dummy_channel_client_disconnect(RedChannelClient *rcc) +{ + DummyChannelClient *self = DUMMY_CHANNEL_CLIENT(rcc); + RedChannel *channel = red_channel_client_get_channel(rcc); + GList *link; + + if (channel && (link = g_list_find(channel->clients, rcc))) { + spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel, + channel->type, channel->id); + red_channel_remove_client(channel, link->data); + } + self->priv->connected = FALSE; +} + +static void +dummy_channel_client_class_init(DummyChannelClientClass *klass) +{ + RedChannelClientClass *cc_class = RED_CHANNEL_CLIENT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(DummyChannelClientPrivate)); + + cc_class->is_connected = dummy_channel_client_is_connected; + cc_class->disconnect = dummy_channel_client_disconnect; +} + +static void +dummy_channel_client_init(DummyChannelClient *self) +{ + self->priv = DUMMY_CHANNEL_CLIENT_PRIVATE(self); + + self->priv->connected = TRUE; +} + +RedChannelClient* dummy_channel_client_create(RedChannel *channel, + RedClient *client, + int num_common_caps, + uint32_t *common_caps, + int num_caps, uint32_t *caps) +{ + RedChannelClient *rcc; + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } + + rcc = g_initable_new(TYPE_DUMMY_CHANNEL_CLIENT, + NULL, NULL, + "channel", channel, + "client", client, + "caps", caps_array, + "common-caps", common_caps_array, + NULL); + + if (caps_array) + g_array_unref(caps_array); + if (common_caps_array) + g_array_unref(common_caps_array); + + return rcc; +} diff --git a/server/dummy-channel-client.h b/server/dummy-channel-client.h new file mode 100644 index 00000000..8013aa25 --- /dev/null +++ b/server/dummy-channel-client.h @@ -0,0 +1,64 @@ +/* + 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_CLIENT_H__ +#define __DUMMY_CHANNEL_CLIENT_H__ + +#include <glib-object.h> + +#include "red-channel-client.h" + +G_BEGIN_DECLS + +#define TYPE_DUMMY_CHANNEL_CLIENT dummy_channel_client_get_type() + +#define DUMMY_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_DUMMY_CHANNEL_CLIENT, DummyChannelClient)) +#define DUMMY_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_DUMMY_CHANNEL_CLIENT, DummyChannelClientClass)) +#define IS_DUMMY_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_DUMMY_CHANNEL_CLIENT)) +#define IS_DUMMY_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_DUMMY_CHANNEL_CLIENT)) +#define DUMMY_CHANNEL_CLIENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_DUMMY_CHANNEL_CLIENT, DummyChannelClientClass)) + +typedef struct DummyChannelClient DummyChannelClient; +typedef struct DummyChannelClientClass DummyChannelClientClass; +typedef struct DummyChannelClientPrivate DummyChannelClientPrivate; + +struct DummyChannelClient +{ + RedChannelClient parent; + + DummyChannelClientPrivate *priv; +}; + +struct DummyChannelClientClass +{ + RedChannelClientClass parent_class; +}; + +GType dummy_channel_client_get_type(void) G_GNUC_CONST; + +RedChannelClient *dummy_channel_client_create(RedChannel *channel, + RedClient *client, + int num_common_caps, uint32_t *common_caps, + int num_caps, uint32_t *caps); + +G_END_DECLS + +#endif /* __DUMMY_CHANNEL_CLIENT_H__ */ diff --git a/server/inputs-channel-client.c b/server/inputs-channel-client.c index 7b386252..76de3820 100644 --- a/server/inputs-channel-client.c +++ b/server/inputs-channel-client.c @@ -19,22 +19,30 @@ #endif #include "inputs-channel-client.h" -#include "inputs-channel.h" #include "migration-protocol.h" #include "red-channel-client.h" -typedef struct InputsChannelClientPrivate InputsChannelClientPrivate; +G_DEFINE_TYPE(InputsChannelClient, inputs_channel_client, RED_TYPE_CHANNEL_CLIENT) + +#define INPUTS_CHANNEL_CLIENT_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_INPUTS_CHANNEL_CLIENT, InputsChannelClientPrivate)) + struct InputsChannelClientPrivate { uint16_t motion_count; }; -struct InputsChannelClient +static void +inputs_channel_client_class_init(InputsChannelClientClass *klass) { - RedChannelClient base; + g_type_class_add_private(klass, sizeof(InputsChannelClientPrivate)); +} - InputsChannelClientPrivate priv[1]; -}; +static void +inputs_channel_client_init(InputsChannelClient *self) +{ + self->priv = INPUTS_CHANNEL_CLIENT_PRIVATE(self); +} RedChannelClient* inputs_channel_client_create(RedChannel *channel, RedClient *client, @@ -45,18 +53,34 @@ RedChannelClient* inputs_channel_client_create(RedChannel *channel, int num_caps, uint32_t *caps) { - InputsChannelClient* icc = - INPUTS_CHANNEL_CLIENT(red_channel_client_create(sizeof(InputsChannelClient), - channel, client, - stream, - monitor_latency, - num_common_caps, - common_caps, num_caps, - caps)); - if (icc) { - icc->priv->motion_count = 0; + RedChannelClient *rcc; + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); } - return RED_CHANNEL_CLIENT(icc); + rcc = g_initable_new(TYPE_INPUTS_CHANNEL_CLIENT, + NULL, NULL, + "channel", channel, + "client", client, + "stream", stream, + "monitor-latency", monitor_latency, + "caps", caps_array, + "common-caps", common_caps_array, + NULL); + + if (caps_array) + g_array_unref(caps_array); + if (common_caps_array) + g_array_unref(common_caps_array); + + return rcc; } void inputs_channel_client_send_migrate_data(RedChannelClient *rcc, diff --git a/server/inputs-channel-client.h b/server/inputs-channel-client.h index 82dbbafa..7550b3cf 100644 --- a/server/inputs-channel-client.h +++ b/server/inputs-channel-client.h @@ -18,9 +18,43 @@ #ifndef _INPUTS_CHANNEL_CLIENT_H_ #define _INPUTS_CHANNEL_CLIENT_H_ -#include "red-channel.h" +#include <glib-object.h> + +#include "red-channel-client.h" +#include "inputs-channel.h" + +G_BEGIN_DECLS + +#define TYPE_INPUTS_CHANNEL_CLIENT inputs_channel_client_get_type() + +#define INPUTS_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_INPUTS_CHANNEL_CLIENT, InputsChannelClient)) +#define INPUTS_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_INPUTS_CHANNEL_CLIENT, InputsChannelClientClass)) +#define IS_INPUTS_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_INPUTS_CHANNEL_CLIENT)) +#define IS_INPUTS_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_INPUTS_CHANNEL_CLIENT)) +#define INPUTS_CHANNEL_CLIENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_INPUTS_CHANNEL_CLIENT, InputsChannelClientClass)) typedef struct InputsChannelClient InputsChannelClient; +typedef struct InputsChannelClientClass InputsChannelClientClass; +typedef struct InputsChannelClientPrivate InputsChannelClientPrivate; + +struct InputsChannelClient +{ + RedChannelClient parent; + + InputsChannelClientPrivate *priv; +}; + +struct InputsChannelClientClass +{ + RedChannelClientClass parent_class; +}; + +GType inputs_channel_client_get_type(void) G_GNUC_CONST; RedChannelClient* inputs_channel_client_create(RedChannel *channel, RedClient *client, @@ -31,12 +65,15 @@ RedChannelClient* inputs_channel_client_create(RedChannel *channel, int num_caps, uint32_t *caps); +uint16_t inputs_channel_client_get_motion_count(InputsChannelClient* self); +/* only for migration */ +void inputs_channel_client_set_motion_count(InputsChannelClient* self, uint16_t count); +void inputs_channel_client_on_mouse_motion(InputsChannelClient* self); void inputs_channel_client_send_migrate_data(RedChannelClient *rcc, - SpiceMarshaller *m, - RedPipeItem *item); -void inputs_channel_client_handle_migrate_data(InputsChannelClient *icc, - uint16_t motion_count); -void inputs_channel_client_on_mouse_motion(InputsChannelClient *icc); + SpiceMarshaller *m, RedPipeItem *item); +void inputs_channel_client_handle_migrate_data(InputsChannelClient *icc, uint16_t motion_count); + +G_END_DECLS enum { RED_PIPE_ITEM_INPUTS_INIT = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, @@ -45,6 +82,4 @@ enum { RED_PIPE_ITEM_MIGRATE_DATA, }; -#define INPUTS_CHANNEL_CLIENT(rcc) ((InputsChannelClient*)rcc) - #endif /* _INPUTS_CHANNEL_CLIENT_H_ */ diff --git a/server/main-channel-client.c b/server/main-channel-client.c index 23907844..9966a387 100644 --- a/server/main-channel-client.c +++ b/server/main-channel-client.c @@ -42,7 +42,11 @@ enum NetTestStage { #define CLIENT_CONNECTIVITY_TIMEOUT (MSEC_PER_SEC * 30) #define PING_INTERVAL (MSEC_PER_SEC * 10) -typedef struct MainChannelClientPrivate MainChannelClientPrivate; +G_DEFINE_TYPE(MainChannelClient, main_channel_client, RED_TYPE_CHANNEL_CLIENT) + +#define MAIN_CHANNEL_CLIENT_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_MAIN_CHANNEL_CLIENT, MainChannelClientPrivate)) + struct MainChannelClientPrivate { uint32_t connection_id; uint32_t ping_id; @@ -62,12 +66,6 @@ struct MainChannelClientPrivate { int seamless_mig_dst; }; -struct MainChannelClient { - RedChannelClient base; - - MainChannelClientPrivate priv[1]; -}; - typedef struct RedPingPipeItem { RedPipeItem base; int size; @@ -126,6 +124,93 @@ typedef struct RedMultiMediaTimePipeItem { static const uint8_t zero_page[ZERO_BUF_SIZE] = {0}; +enum { + PROP0, + PROP_CONNECTION_ID +}; + +static void main_channel_client_get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + MainChannelClient *self = MAIN_CHANNEL_CLIENT(object); + + switch (property_id) + { + case PROP_CONNECTION_ID: + g_value_set_uint(value, self->priv->connection_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void main_channel_client_set_property(GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + MainChannelClient *self = MAIN_CHANNEL_CLIENT(object); + + switch (property_id) + { + case PROP_CONNECTION_ID: + self->priv->connection_id = g_value_get_uint(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void ping_timer_cb(void *opaque); +static void main_channel_client_constructed(GObject *object) +{ + G_OBJECT_CLASS(main_channel_client_parent_class)->constructed(object); +#ifdef RED_STATISTICS + MainChannelClient *self = MAIN_CHANNEL_CLIENT(object); + RedsState *reds = + red_channel_get_server(red_channel_client_get_channel(RED_CHANNEL_CLIENT(object))); + + self->priv->ping_timer = + reds_get_core_interface(reds)->timer_add(reds_get_core_interface(reds), + ping_timer_cb, self); + if (!self->priv->ping_timer) { + spice_error("ping timer create failed"); + } + self->priv->ping_interval = PING_INTERVAL; +#endif +} + +static void main_channel_client_class_init(MainChannelClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(MainChannelClientPrivate)); + + object_class->get_property = main_channel_client_get_property; + object_class->set_property = main_channel_client_set_property; + object_class->constructed = main_channel_client_constructed; + + g_object_class_install_property(object_class, + PROP_CONNECTION_ID, + g_param_spec_uint("connection-id", + "Connection ID", + "Connection ID", + 0, + G_MAXUINT, + 0, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +static void main_channel_client_init(MainChannelClient *self) +{ + self->priv = MAIN_CHANNEL_CLIENT_PRIVATE(self); + self->priv->bitrate_per_sec = ~0; +} + static int main_channel_client_push_ping(MainChannelClient *mcc, int size); static void main_notify_item_free(RedPipeItem *base) @@ -556,19 +641,35 @@ MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient int num_common_caps, uint32_t *common_caps, int num_caps, uint32_t *caps) { - MainChannelClient *mcc = MAIN_CHANNEL_CLIENT( - red_channel_client_create(sizeof(MainChannelClient), &main_chan->base, - client, stream, FALSE, num_common_caps, - common_caps, num_caps, caps)); - spice_assert(mcc != NULL); - mcc->priv->connection_id = connection_id; - mcc->priv->bitrate_per_sec = ~0; -#ifdef RED_STATISTICS - if (!(mcc->priv->ping_timer = reds_core_timer_add(red_channel_get_server(&main_chan->base), ping_timer_cb, mcc))) { - spice_error("ping timer create failed"); + MainChannelClient *mcc; + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); } - mcc->priv->ping_interval = PING_INTERVAL; -#endif + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } + + mcc = g_initable_new(TYPE_MAIN_CHANNEL_CLIENT, + NULL, NULL, + "channel", RED_CHANNEL(main_chan), + "client", client, + "stream", stream, + "monitor-latency", FALSE, + "caps", caps_array, + "common-caps", common_caps_array, + "connection-id", connection_id, + NULL); + + if (caps_array) + g_array_unref(caps_array); + if (common_caps_array) + g_array_unref(common_caps_array); + return mcc; } diff --git a/server/main-channel-client.h b/server/main-channel-client.h index 3bb87296..360c61e9 100644 --- a/server/main-channel-client.h +++ b/server/main-channel-client.h @@ -17,11 +17,46 @@ #ifndef __MAIN_CHANNEL_CLIENT_H__ #define __MAIN_CHANNEL_CLIENT_H__ -#include "red-channel.h" +#include <glib-object.h> +#include <common/messages.h> + +#include "red-channel-client.h" + +G_BEGIN_DECLS /* FIXME: remove extra MainChannel typedef when possible */ 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)) +#define MAIN_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_MAIN_CHANNEL_CLIENT, MainChannelClientClass)) +#define IS_MAIN_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_MAIN_CHANNEL_CLIENT)) +#define IS_MAIN_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_MAIN_CHANNEL_CLIENT)) +#define MAIN_CHANNEL_CLIENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_MAIN_CHANNEL_CLIENT, MainChannelClientClass)) + typedef struct MainChannelClient MainChannelClient; +typedef struct MainChannelClientClass MainChannelClientClass; +typedef struct MainChannelClientPrivate MainChannelClientPrivate; + +struct MainChannelClient +{ + RedChannelClient parent; + + MainChannelClientPrivate *priv; +}; + +struct MainChannelClientClass +{ + RedChannelClientClass parent_class; +}; + +GType main_channel_client_get_type(void) G_GNUC_CONST; MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient *client, RedsStream *stream, uint32_t connection_id, @@ -105,6 +140,6 @@ typedef struct MainMultiMediaTimeItemInfo { RedPipeItem *main_multi_media_time_item_new(RedChannelClient *rcc, void *data, int num); -#define MAIN_CHANNEL_CLIENT(rcc) ((MainChannelClient*)rcc) +G_END_DECLS #endif /* __MAIN_CHANNEL_CLIENT_H__ */ diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h index 804b39a5..f94e042d 100644 --- a/server/red-channel-client-private.h +++ b/server/red-channel-client-private.h @@ -19,14 +19,14 @@ #define _H_RED_CHANNEL_CLIENT_PRIVATE #include "red-channel.h" +#include "red-channel-client.h" struct RedChannelClientPrivate { RedChannel *channel; RedClient *client; RedsStream *stream; - int dummy; - int dummy_connected; + gboolean monitor_latency; uint32_t refs; diff --git a/server/red-channel-client.c b/server/red-channel-client.c index c59e4d0e..e860390c 100644 --- a/server/red-channel-client.c +++ b/server/red-channel-client.c @@ -37,6 +37,32 @@ #include "red-channel-client-private.h" #include "red-channel.h" +static const SpiceDataHeaderOpaque full_header_wrapper; +static const SpiceDataHeaderOpaque mini_header_wrapper; +static void red_channel_client_destroy_remote_caps(RedChannelClient* rcc); +static void red_channel_client_initable_interface_init(GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE(RedChannelClient, red_channel_client, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, + red_channel_client_initable_interface_init)) + +#define CHANNEL_CLIENT_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), RED_TYPE_CHANNEL_CLIENT, RedChannelClientPrivate)) + +static gboolean red_channel_client_initable_init(GInitable *initable, + GCancellable *cancellable, + GError **error); + +enum { + PROP0, + PROP_STREAM, + PROP_CHANNEL, + PROP_CLIENT, + PROP_MONITOR_LATENCY, + PROP_COMMON_CAPS, + PROP_CAPS +}; + #define PING_TEST_TIMEOUT_MS (MSEC_PER_SEC * 15) #define PING_TEST_IDLE_NET_TIMEOUT_MS (MSEC_PER_SEC / 10) @@ -102,6 +128,226 @@ static void red_channel_client_restart_ping_timer(RedChannelClient *rcc) red_channel_client_start_ping_timer(rcc, timeout); } +static void +red_channel_client_get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + RedChannelClient *self = RED_CHANNEL_CLIENT(object); + + switch (property_id) + { + case PROP_STREAM: + g_value_set_pointer(value, self->priv->stream); + break; + case PROP_CHANNEL: + g_value_set_pointer(value, self->priv->channel); + break; + case PROP_CLIENT: + g_value_set_pointer(value, self->priv->client); + break; + case PROP_MONITOR_LATENCY: + g_value_set_boolean(value, self->priv->monitor_latency); + break; + case PROP_COMMON_CAPS: + { + GArray *arr = g_array_sized_new(FALSE, FALSE, + sizeof(*self->priv->remote_caps.common_caps), + self->priv->remote_caps.num_common_caps); + g_value_take_boxed(value, arr); + } + break; + case PROP_CAPS: + { + GArray *arr = g_array_sized_new(FALSE, FALSE, + sizeof(*self->priv->remote_caps.caps), + self->priv->remote_caps.num_caps); + g_value_take_boxed(value, arr); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void +red_channel_client_set_property(GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + RedChannelClient *self = RED_CHANNEL_CLIENT(object); + + switch (property_id) + { + case PROP_STREAM: + self->priv->stream = g_value_get_pointer(value); + break; + case PROP_CHANNEL: + if (self->priv->channel) + red_channel_unref(self->priv->channel); + self->priv->channel = g_value_get_pointer(value); + if (self->priv->channel) + red_channel_ref(self->priv->channel); + break; + case PROP_CLIENT: + self->priv->client = g_value_get_pointer(value); + break; + case PROP_MONITOR_LATENCY: + self->priv->monitor_latency = g_value_get_boolean(value); + break; + case PROP_COMMON_CAPS: + { + GArray *caps = g_value_get_boxed(value); + if (caps) { + self->priv->remote_caps.num_common_caps = caps->len; + free(self->priv->remote_caps.common_caps); + self->priv->remote_caps.common_caps = + spice_memdup(caps->data, caps->len * sizeof(uint32_t)); + } + } + break; + case PROP_CAPS: + { + GArray *caps = g_value_get_boxed(value); + if (caps) { + self->priv->remote_caps.num_caps = caps->len; + free(self->priv->remote_caps.caps); + self->priv->remote_caps.caps = + spice_memdup(caps->data, caps->len * sizeof(uint32_t)); + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void +red_channel_client_finalize(GObject *object) +{ + RedChannelClient *self = RED_CHANNEL_CLIENT(object); + + reds_stream_free(self->priv->stream); + self->priv->stream = NULL; + + if (self->priv->send_data.main.marshaller) { + spice_marshaller_destroy(self->priv->send_data.main.marshaller); + } + + if (self->priv->send_data.urgent.marshaller) { + spice_marshaller_destroy(self->priv->send_data.urgent.marshaller); + } + + red_channel_client_destroy_remote_caps(self); + if (self->priv->channel) { + red_channel_unref(self->priv->channel); + } + + G_OBJECT_CLASS(red_channel_client_parent_class)->finalize(object); +} + +static void red_channel_client_initable_interface_init(GInitableIface *iface) +{ + iface->init = red_channel_client_initable_init; +} + +static gboolean red_channel_client_default_is_connected(RedChannelClient *rcc); +static void red_channel_client_default_disconnect(RedChannelClient *rcc); + + +static void red_channel_client_constructed(GObject *object) +{ + RedChannelClient *self = RED_CHANNEL_CLIENT(object); + + if (red_channel_client_test_remote_common_cap(self, SPICE_COMMON_CAP_MINI_HEADER)) { + self->incoming.header = mini_header_wrapper; + self->priv->send_data.header = mini_header_wrapper; + self->priv->is_mini_header = TRUE; + } else { + self->incoming.header = full_header_wrapper; + self->priv->send_data.header = full_header_wrapper; + self->priv->is_mini_header = FALSE; + } +} + +static void red_channel_client_class_init(RedChannelClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GParamSpec *spec; + + g_debug("%s", G_STRFUNC); + g_type_class_add_private(klass, sizeof(RedChannelClientPrivate)); + + object_class->get_property = red_channel_client_get_property; + object_class->set_property = red_channel_client_set_property; + object_class->finalize = red_channel_client_finalize; + object_class->constructed = red_channel_client_constructed; + + klass->is_connected = red_channel_client_default_is_connected; + klass->disconnect = red_channel_client_default_disconnect; + + spec = g_param_spec_pointer("stream", "stream", + "Associated RedStream", + G_PARAM_STATIC_STRINGS + | G_PARAM_READWRITE + | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(object_class, PROP_STREAM, spec); + + spec = g_param_spec_pointer("channel", "channel", + "Associated RedChannel", + G_PARAM_STATIC_STRINGS + | G_PARAM_READWRITE + | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(object_class, PROP_CHANNEL, spec); + + spec = g_param_spec_pointer("client", "client", + "Associated RedClient", + G_PARAM_STATIC_STRINGS + | G_PARAM_READWRITE + | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(object_class, PROP_CLIENT, spec); + + spec = g_param_spec_boolean("monitor-latency", "monitor-latency", + "Whether to monitor latency for this client", + FALSE, + G_PARAM_STATIC_STRINGS + | G_PARAM_READWRITE + | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(object_class, PROP_MONITOR_LATENCY, spec); + + spec = g_param_spec_boxed("common-caps", "common-caps", + "Common Capabilities", + G_TYPE_ARRAY, + G_PARAM_STATIC_STRINGS + | G_PARAM_READWRITE + | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(object_class, PROP_COMMON_CAPS, spec); + + spec = g_param_spec_boxed("caps", "caps", + "Capabilities", + G_TYPE_ARRAY, + G_PARAM_STATIC_STRINGS + | G_PARAM_READWRITE + | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(object_class, PROP_CAPS, spec); +} + +static void +red_channel_client_init(RedChannelClient *self) +{ + self->priv = CHANNEL_CLIENT_PRIVATE(self); + // blocks send message (maybe use send_data.blocked + block flags) + self->priv->ack_data.messages_window = ~0; + self->priv->ack_data.client_generation = ~0; + self->priv->ack_data.client_window = CLIENT_ACK_WINDOW; + self->priv->send_data.main.marshaller = spice_marshaller_new(); + self->priv->send_data.urgent.marshaller = spice_marshaller_new(); + + self->priv->send_data.marshaller = self->priv->send_data.main.marshaller; +} + RedChannel* red_channel_client_get_channel(RedChannelClient *rcc) { return rcc->priv->channel; @@ -336,19 +582,6 @@ static gboolean red_channel_client_pipe_remove(RedChannelClient *rcc, RedPipeIte return g_queue_remove(&rcc->priv->pipe, item); } -static void red_channel_client_set_remote_caps(RedChannelClient* rcc, - int num_common_caps, uint32_t *common_caps, - int num_caps, uint32_t *caps) -{ - rcc->priv->remote_caps.num_common_caps = num_common_caps; - rcc->priv->remote_caps.common_caps = spice_memdup(common_caps, - num_common_caps * - sizeof(uint32_t)); - - rcc->priv->remote_caps.num_caps = num_caps; - rcc->priv->remote_caps.caps = spice_memdup(caps, num_caps * sizeof(uint32_t)); -} - static void red_channel_client_destroy_remote_caps(RedChannelClient* rcc) { rcc->priv->remote_caps.num_common_caps = 0; @@ -510,14 +743,14 @@ static void red_channel_client_event(int fd, int event, void *data) { RedChannelClient *rcc = RED_CHANNEL_CLIENT(data); - red_channel_client_ref(rcc); + g_object_ref(rcc); if (event & SPICE_WATCH_EVENT_READ) { red_channel_client_receive(rcc); } if (event & SPICE_WATCH_EVENT_WRITE) { red_channel_client_push(rcc); } - red_channel_client_unref(rcc); + g_object_unref(rcc); } static uint32_t full_header_get_msg_size(SpiceDataHeaderOpaque *header) @@ -606,129 +839,108 @@ static int red_channel_client_pre_create_validate(RedChannel *channel, RedClient return TRUE; } -RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedClient *client, - RedsStream *stream, - int monitor_latency, - int num_common_caps, uint32_t *common_caps, - int num_caps, uint32_t *caps) -{ - RedChannelClient *rcc = NULL; - - pthread_mutex_lock(&client->lock); - if (!red_channel_client_pre_create_validate(channel, client)) { - goto error; - } - spice_assert(stream && channel && size >= sizeof(RedChannelClient)); - rcc = spice_malloc0(size); - rcc->priv->stream = stream; - rcc->priv->channel = channel; - rcc->priv->client = client; - rcc->priv->refs = 1; - rcc->priv->ack_data.messages_window = ~0; // blocks send message (maybe use send_data.blocked + - // block flags) - rcc->priv->ack_data.client_generation = ~0; - rcc->priv->ack_data.client_window = CLIENT_ACK_WINDOW; - rcc->priv->send_data.main.marshaller = spice_marshaller_new(); - rcc->priv->send_data.urgent.marshaller = spice_marshaller_new(); - - rcc->priv->send_data.marshaller = rcc->priv->send_data.main.marshaller; - - rcc->incoming.opaque = rcc; - rcc->incoming.cb = &channel->incoming_cb; - - rcc->outgoing.opaque = rcc; - rcc->outgoing.cb = &channel->outgoing_cb; - rcc->outgoing.pos = 0; - rcc->outgoing.size = 0; - - red_channel_client_set_remote_caps(rcc, num_common_caps, common_caps, num_caps, caps); - if (red_channel_client_test_remote_common_cap(rcc, SPICE_COMMON_CAP_MINI_HEADER)) { - rcc->incoming.header = mini_header_wrapper; - rcc->priv->send_data.header = mini_header_wrapper; - rcc->priv->is_mini_header = TRUE; - } else { - rcc->incoming.header = full_header_wrapper; - rcc->priv->send_data.header = full_header_wrapper; - rcc->priv->is_mini_header = FALSE; +static gboolean red_channel_client_initable_init(GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + GError *local_error = NULL; + 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)) { + 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); + goto cleanup; + } + + 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); + + if (!self->priv->client->during_target_migrate) { + red_channel_client_start_ping_timer(self, + PING_TEST_IDLE_NET_TIMEOUT_MS); + } + self->priv->latency_monitor.roundtrip = -1; } - rcc->incoming.header.data = rcc->incoming.header_buf; - - if (!channel->channel_cbs.config_socket(rcc)) { - goto error; - } + self->incoming.opaque = self; + self->incoming.cb = &self->priv->channel->incoming_cb; + self->incoming.header.data = self->incoming.header_buf; - g_queue_init(&rcc->priv->pipe); + self->outgoing.opaque = self; + self->outgoing.cb = &self->priv->channel->outgoing_cb; + self->outgoing.pos = 0; + self->outgoing.size = 0; - stream->watch = channel->core->watch_add(channel->core, - stream->socket, - SPICE_WATCH_EVENT_READ, - red_channel_client_event, rcc); - rcc->priv->id = g_list_length(channel->clients); - red_channel_add_client(channel, rcc); - red_client_add_channel(client, rcc); - red_channel_ref(channel); - pthread_mutex_unlock(&client->lock); + g_queue_init(&self->priv->pipe); + 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 = g_list_length(self->priv->channel->clients); + red_channel_add_client(self->priv->channel, self); + red_client_add_channel(self->priv->client, self); - if (monitor_latency && reds_stream_get_family(stream) != AF_UNIX) { - rcc->priv->latency_monitor.timer = channel->core->timer_add( - channel->core, red_channel_client_ping_timer, rcc); - if (!client->during_target_migrate) { - red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS); - } - rcc->priv->latency_monitor.roundtrip = -1; + if (!self->priv->channel->channel_cbs.config_socket(self)) { + g_set_error_literal(&local_error, + SPICE_SERVER_ERROR, + SPICE_SERVER_ERROR_FAILED, + "Unable to configure socket"); } - return rcc; -error: - free(rcc); - reds_stream_free(stream); - pthread_mutex_unlock(&client->lock); - return NULL; -} - -RedChannelClient *red_channel_client_create_dummy(int size, - RedChannel *channel, - RedClient *client, - int num_common_caps, uint32_t *common_caps, - int num_caps, uint32_t *caps) -{ - RedChannelClient *rcc = NULL; - - spice_assert(size >= sizeof(RedChannelClient)); - - pthread_mutex_lock(&client->lock); - if (!red_channel_client_pre_create_validate(channel, client)) { - goto error; - } - rcc = spice_malloc0(size); - rcc->priv->refs = 1; - rcc->priv->client = client; - rcc->priv->channel = channel; - red_channel_ref(channel); - red_channel_client_set_remote_caps(rcc, num_common_caps, common_caps, num_caps, caps); - if (red_channel_client_test_remote_common_cap(rcc, SPICE_COMMON_CAP_MINI_HEADER)) { - rcc->incoming.header = mini_header_wrapper; - rcc->priv->send_data.header = mini_header_wrapper; - rcc->priv->is_mini_header = TRUE; - } else { - rcc->incoming.header = full_header_wrapper; - rcc->priv->send_data.header = full_header_wrapper; - rcc->priv->is_mini_header = FALSE; +cleanup: + pthread_mutex_unlock(&self->priv->client->lock); + if (local_error) { + g_warning("Failed to create channel client: %s", local_error->message); + g_propagate_error(error, local_error); } + return local_error == NULL; +} - rcc->incoming.header.data = rcc->incoming.header_buf; - g_queue_init(&rcc->priv->pipe); +RedChannelClient *red_channel_client_create(RedChannel *channel, RedClient *client, + RedsStream *stream, + int monitor_latency, + int num_common_caps, uint32_t *common_caps, + int num_caps, uint32_t *caps) +{ + RedChannelClient *rcc; + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } + rcc = g_initable_new(RED_TYPE_CHANNEL_CLIENT, + NULL, NULL, + "channel", channel, + "client", client, + "stream", stream, + "monitor-latency", monitor_latency, + "caps", caps_array, + "common-caps", common_caps_array, + NULL); + + if (caps_array) + g_array_unref(caps_array); + if (common_caps_array) + g_array_unref(common_caps_array); - rcc->priv->dummy = TRUE; - rcc->priv->dummy_connected = TRUE; - red_channel_add_client(channel, rcc); - red_client_add_channel(client, rcc); - pthread_mutex_unlock(&client->lock); return rcc; -error: - pthread_mutex_unlock(&client->lock); - return NULL; } static void red_channel_client_seamless_migration_done(RedChannelClient *rcc) @@ -772,43 +984,12 @@ void red_channel_client_default_migrate(RedChannelClient *rcc) red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_MIGRATE); } -void red_channel_client_ref(RedChannelClient *rcc) -{ - rcc->priv->refs++; -} - -void red_channel_client_unref(RedChannelClient *rcc) -{ - if (--rcc->priv->refs != 0) { - return; - } - - spice_debug("destroy rcc=%p", rcc); - - reds_stream_free(rcc->priv->stream); - rcc->priv->stream = NULL; - - if (rcc->priv->send_data.main.marshaller) { - spice_marshaller_destroy(rcc->priv->send_data.main.marshaller); - } - - if (rcc->priv->send_data.urgent.marshaller) { - spice_marshaller_destroy(rcc->priv->send_data.urgent.marshaller); - } - - red_channel_client_destroy_remote_caps(rcc); - if (rcc->priv->channel) { - red_channel_unref(rcc->priv->channel); - } - free(rcc); -} - void red_channel_client_destroy(RedChannelClient *rcc) { rcc->priv->destroying = TRUE; red_channel_client_disconnect(rcc); red_client_remove_channel(rcc); - red_channel_client_unref(rcc); + g_object_unref(rcc); } void red_channel_client_shutdown(RedChannelClient *rcc) @@ -1000,16 +1181,16 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle void red_channel_client_receive(RedChannelClient *rcc) { - red_channel_client_ref(rcc); + g_object_ref(rcc); red_peer_handle_incoming(rcc->priv->stream, &rcc->incoming); - red_channel_client_unref(rcc); + g_object_unref(rcc); } void red_channel_client_send(RedChannelClient *rcc) { - red_channel_client_ref(rcc); + g_object_ref(rcc); red_peer_handle_outgoing(rcc->priv->stream, &rcc->outgoing); - red_channel_client_unref(rcc); + g_object_unref(rcc); } static inline RedPipeItem *red_channel_client_pipe_item_get(RedChannelClient *rcc) @@ -1030,7 +1211,7 @@ void red_channel_client_push(RedChannelClient *rcc) } else { return; } - red_channel_client_ref(rcc); + g_object_ref(rcc); if (rcc->priv->send_data.blocked) { red_channel_client_send(rcc); } @@ -1049,7 +1230,7 @@ void red_channel_client_push(RedChannelClient *rcc) SPICE_WATCH_EVENT_READ); } rcc->priv->during_send = FALSE; - red_channel_client_unref(rcc); + g_object_unref(rcc); } int red_channel_client_get_roundtrip_ms(RedChannelClient *rcc) @@ -1377,14 +1558,18 @@ gboolean red_channel_client_is_mini_header(RedChannelClient *rcc) return rcc->priv->is_mini_header; } -int red_channel_client_is_connected(RedChannelClient *rcc) +static gboolean red_channel_client_default_is_connected(RedChannelClient *rcc) { - if (!rcc->priv->dummy) { - return rcc->priv->channel - && (g_list_find(rcc->priv->channel->clients, rcc) != NULL); - } else { - return rcc->priv->dummy_connected; - } + return rcc->priv->channel + && (g_list_find(rcc->priv->channel->clients, rcc) != NULL); +} + +gboolean red_channel_client_is_connected(RedChannelClient *rcc) +{ + RedChannelClientClass *klass = RED_CHANNEL_CLIENT_GET_CLASS(rcc); + + g_return_val_if_fail(klass->is_connected != NULL, FALSE); + return klass->is_connected(rcc); } static void red_channel_client_clear_sent_item(RedChannelClient *rcc) @@ -1424,27 +1609,10 @@ void red_channel_client_push_set_ack(RedChannelClient *rcc) red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_SET_ACK); } -static void red_channel_client_disconnect_dummy(RedChannelClient *rcc) -{ - RedChannel *channel = red_channel_client_get_channel(rcc); - GList *link; - spice_assert(rcc->priv->dummy); - if (channel && (link = g_list_find(channel->clients, rcc))) { - spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel, - channel->type, channel->id); - red_channel_remove_client(channel, link->data); - } - rcc->priv->dummy_connected = FALSE; -} - -void red_channel_client_disconnect(RedChannelClient *rcc) +static void red_channel_client_default_disconnect(RedChannelClient *rcc) { RedChannel *channel = rcc->priv->channel; - if (rcc->priv->dummy) { - red_channel_client_disconnect_dummy(rcc); - return; - } if (!red_channel_client_is_connected(rcc)) { return; } @@ -1467,6 +1635,14 @@ void red_channel_client_disconnect(RedChannelClient *rcc) channel->channel_cbs.on_disconnect(rcc); } +void red_channel_client_disconnect(RedChannelClient *rcc) +{ + RedChannelClientClass *klass = RED_CHANNEL_CLIENT_GET_CLASS(rcc); + + g_return_if_fail(klass->is_connected != NULL); + klass->disconnect(rcc); +} + int red_channel_client_is_blocked(RedChannelClient *rcc) { return rcc && rcc->priv->send_data.blocked; @@ -1644,3 +1820,8 @@ gboolean red_channel_client_is_destroying(RedChannelClient *rcc) { return rcc->priv->destroying; } + +GQuark spice_server_error_quark(void) +{ + return g_quark_from_static_string("spice-server-error-quark"); +} diff --git a/server/red-channel-client.h b/server/red-channel-client.h index 5bfac3a6..0b180b3e 100644 --- a/server/red-channel-client.h +++ b/server/red-channel-client.h @@ -18,21 +18,47 @@ #ifndef _H_RED_CHANNEL_CLIENT #define _H_RED_CHANNEL_CLIENT +#include <glib-object.h> +#include <gio/gio.h> +#include <spice/protocol.h> #include <common/marshaller.h> #include "red-pipe-item.h" #include "reds-stream.h" #include "red-channel.h" -/* FIXME: remove */ -#include "red-channel-client-private.h" + +G_BEGIN_DECLS + +#define MAX_HEADER_SIZE sizeof(SpiceDataHeader) +#define CLIENT_ACK_WINDOW 20 + +#ifndef IOV_MAX +#define IOV_MAX 1024 +#endif + +#define RED_TYPE_CHANNEL_CLIENT red_channel_client_get_type() + +#define RED_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHANNEL_CLIENT, RedChannelClient)) +#define RED_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHANNEL_CLIENT, RedChannelClientClass)) +#define RED_IS_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHANNEL_CLIENT)) +#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 RedChannelClient RedChannelClient; +typedef struct RedChannelClientClass RedChannelClientClass; typedef struct RedChannelClientPrivate RedChannelClientPrivate; +GType red_channel_client_get_type(void) G_GNUC_CONST; + /* * When an error occurs over a channel, we treat it as a warning * for spice-server and shutdown the channel. @@ -45,22 +71,13 @@ typedef struct RedChannelClientPrivate RedChannelClientPrivate; red_channel_client_shutdown(rcc); \ } while (0) -RedChannelClient *red_channel_client_create(int size, RedChannel *channel, +RedChannelClient *red_channel_client_create(RedChannel *channel, RedClient *client, RedsStream *stream, int monitor_latency, int num_common_caps, uint32_t *common_caps, int num_caps, uint32_t *caps); -RedChannelClient *red_channel_client_create_dummy(int size, - RedChannel *channel, - RedClient *client, - int num_common_caps, uint32_t *common_caps, - int num_caps, uint32_t *caps); - -void red_channel_client_ref(RedChannelClient *rcc); -void red_channel_client_unref(RedChannelClient *rcc); - -int red_channel_client_is_connected(RedChannelClient *rcc); +gboolean red_channel_client_is_connected(RedChannelClient *rcc); void red_channel_client_default_migrate(RedChannelClient *rcc); int red_channel_client_is_waiting_for_migrate_data(RedChannelClient *rcc); void red_channel_client_destroy(RedChannelClient *rcc); @@ -175,8 +192,6 @@ gboolean red_channel_client_set_migration_seamless(RedChannelClient *rcc); void red_channel_client_set_destroying(RedChannelClient *rcc); gboolean red_channel_client_is_destroying(RedChannelClient *rcc); -#define RED_CHANNEL_CLIENT(Client) ((RedChannelClient *)(Client)) - typedef struct OutgoingHandler { OutgoingHandlerInterface *cb; void *opaque; @@ -197,12 +212,48 @@ typedef struct IncomingHandler { uint32_t msg_pos; } IncomingHandler; -struct RedChannelClient { +struct RedChannelClient +{ + GObject parent; + /* protected */ OutgoingHandler outgoing; IncomingHandler incoming; - RedChannelClientPrivate priv[1]; + RedChannelClientPrivate *priv; +}; + +struct RedChannelClientClass +{ + GObjectClass parent_class; + + gboolean (*is_connected)(RedChannelClient *rcc); + void (*disconnect)(RedChannelClient *rcc); +}; + +#define SPICE_SERVER_ERROR spice_server_error_quark() +GQuark spice_server_error_quark(void); + +typedef enum +{ + SPICE_SERVER_ERROR_FAILED +} SpiceServerError; + +/* Messages handled by red_channel + * SET_ACK - sent to client on channel connection + * Note that the numbers don't have to correspond to spice message types, + * but we keep the 100 first allocated for base channel approach. + * */ +enum { + RED_PIPE_ITEM_TYPE_SET_ACK=1, + RED_PIPE_ITEM_TYPE_MIGRATE, + RED_PIPE_ITEM_TYPE_EMPTY_MSG, + RED_PIPE_ITEM_TYPE_PING, + RED_PIPE_ITEM_TYPE_MARKER, + + RED_PIPE_ITEM_TYPE_CHANNEL_BASE=101, }; +G_END_DECLS + #endif /* _H_RED_CHANNEL_CLIENT */ diff --git a/server/red-channel.h b/server/red-channel.h index fc59deec..8818a043 100644 --- a/server/red-channel.h +++ b/server/red-channel.h @@ -27,26 +27,13 @@ #include <common/ring.h> #include <common/marshaller.h> +#include "demarshallers.h" #include "spice.h" #include "red-common.h" -#include "demarshallers.h" #include "reds-stream.h" #include "stat.h" #include "red-pipe-item.h" -#define MAX_SEND_BUFS 1000 -#define CLIENT_ACK_WINDOW 20 - -#ifndef IOV_MAX -#define IOV_MAX 1024 -#endif - -#define MAX_HEADER_SIZE sizeof(SpiceDataHeader) - -/* Basic interface for channels, without using the RedChannel interface. - The intention is to move towards one channel interface gradually. - At the final stage, this interface shouldn't be exposed. Only RedChannel will use it. */ - typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque; typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header); @@ -104,7 +91,6 @@ typedef struct OutgoingHandlerInterface { on_outgoing_msg_done_proc on_msg_done; on_output_proc on_output; } OutgoingHandlerInterface; - /* Red Channel interface */ typedef struct RedChannel RedChannel; @@ -112,21 +98,6 @@ typedef struct RedChannelClient RedChannelClient; typedef struct RedClient RedClient; typedef struct MainChannelClient MainChannelClient; -/* Messages handled by red_channel - * SET_ACK - sent to client on channel connection - * Note that the numbers don't have to correspond to spice message types, - * but we keep the 100 first allocated for base channel approach. - * */ -enum { - RED_PIPE_ITEM_TYPE_SET_ACK=1, - RED_PIPE_ITEM_TYPE_MIGRATE, - RED_PIPE_ITEM_TYPE_EMPTY_MSG, - RED_PIPE_ITEM_TYPE_PING, - RED_PIPE_ITEM_TYPE_MARKER, - - RED_PIPE_ITEM_TYPE_CHANNEL_BASE=101, -}; - typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient *channel, uint16_t type, uint32_t size); typedef int (*channel_handle_parsed_proc)(RedChannelClient *rcc, uint32_t size, uint16_t type, diff --git a/server/smartcard-channel-client.c b/server/smartcard-channel-client.c index 0622be5c..ec99e07f 100644 --- a/server/smartcard-channel-client.c +++ b/server/smartcard-channel-client.c @@ -20,12 +20,123 @@ #include "smartcard-channel-client.h" +G_DEFINE_TYPE(SmartCardChannelClient, smart_card_channel_client, RED_TYPE_CHANNEL_CLIENT) + +#define SMARTCARD_CHANNEL_CLIENT_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_SMARTCARD_CHANNEL_CLIENT, \ + SmartCardChannelClientPrivate)) + +struct SmartCardChannelClientPrivate +{ + RedCharDeviceSmartcard *smartcard; + + /* read_from_client/write_to_device buffer. + * The beginning of the buffer should always be VSCMsgHeader*/ + RedCharDeviceWriteBuffer *write_buf; + int msg_in_write_buf; /* was the client msg received into a RedCharDeviceWriteBuffer + * or was it explicitly malloced */ +}; + typedef struct RedErrorItem { RedPipeItem base; VSCMsgHeader vheader; VSCMsgError error; } RedErrorItem; +static void smart_card_channel_client_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 smart_card_channel_client_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 smart_card_channel_client_dispose(GObject *object) +{ + G_OBJECT_CLASS(smart_card_channel_client_parent_class)->dispose(object); +} + +static void smart_card_channel_client_finalize(GObject *object) +{ + SmartCardChannelClient *self = SMARTCARD_CHANNEL_CLIENT(object); + + if (self->priv->smartcard) + g_object_remove_weak_pointer(G_OBJECT(self->priv->smartcard), + (gpointer*)&self->priv->smartcard); + G_OBJECT_CLASS(smart_card_channel_client_parent_class)->finalize(object); +} + +static void smart_card_channel_client_class_init(SmartCardChannelClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(SmartCardChannelClientPrivate)); + + object_class->get_property = smart_card_channel_client_get_property; + object_class->set_property = smart_card_channel_client_set_property; + object_class->dispose = smart_card_channel_client_dispose; + object_class->finalize = smart_card_channel_client_finalize; +} + +static void +smart_card_channel_client_init(SmartCardChannelClient *self) +{ + self->priv = SMARTCARD_CHANNEL_CLIENT_PRIVATE(self); +} + +SmartCardChannelClient* smartcard_channel_client_create(RedChannel *channel, + RedClient *client, RedsStream *stream, + int monitor_latency, + int num_common_caps, uint32_t *common_caps, + int num_caps, uint32_t *caps) +{ + SmartCardChannelClient *rcc; + GArray *common_caps_array = NULL, *caps_array = NULL; + + if (common_caps) { + common_caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*common_caps), + num_common_caps); + g_array_append_vals(common_caps_array, common_caps, num_common_caps); + } + if (caps) { + caps_array = g_array_sized_new(FALSE, FALSE, sizeof (*caps), num_caps); + g_array_append_vals(caps_array, caps, num_caps); + } + + rcc = g_initable_new(RED_TYPE_CHANNEL_CLIENT, + NULL, NULL, + "channel", channel, + "client", client, + "stream", stream, + "monitor-latency", monitor_latency, + "caps", caps_array, + "common-caps", common_caps_array, + NULL); + + if (caps_array) + g_array_unref(caps_array); + if (common_caps_array) + g_array_unref(common_caps_array); + + return rcc; +} + uint8_t *smartcard_channel_client_alloc_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) @@ -290,7 +401,14 @@ void smartcard_channel_client_set_char_device(SmartCardChannelClient *scc, return; } + if (scc->priv->smartcard) { + g_object_remove_weak_pointer(G_OBJECT(scc->priv->smartcard), + (gpointer*)&scc->priv->smartcard); + } + scc->priv->smartcard = device; + g_object_add_weak_pointer(G_OBJECT(scc->priv->smartcard), + (gpointer*)&scc->priv->smartcard); } RedCharDeviceSmartcard* smartcard_channel_client_get_char_device(SmartCardChannelClient *scc) diff --git a/server/smartcard-channel-client.h b/server/smartcard-channel-client.h index 44a966a8..4fe1c72b 100644 --- a/server/smartcard-channel-client.h +++ b/server/smartcard-channel-client.h @@ -18,27 +18,42 @@ #ifndef SMARTCARD_CHANNEL_CLIENT_H__ #define SMARTCARD_CHANNEL_CLIENT_H__ +#include <glib-object.h> + #include "smartcard.h" -#include "red-channel-client.h" +G_BEGIN_DECLS + +#define TYPE_SMARTCARD_CHANNEL_CLIENT smart_card_channel_client_get_type() + +#define SMARTCARD_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_SMARTCARD_CHANNEL_CLIENT, SmartCardChannelClient)) +#define SMARTCARD_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_SMARTCARD_CHANNEL_CLIENT, SmartCardChannelClientClass)) +#define IS_SMARTCARD_CHANNEL_CLIENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_SMARTCARD_CHANNEL_CLIENT)) +#define IS_SMARTCARD_CHANNEL_CLIENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_SMARTCARD_CHANNEL_CLIENT)) +#define SMARTCARD_CHANNEL_CLIENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_SMARTCARD_CHANNEL_CLIENT, SmartCardChannelClientClass)) + +typedef struct SmartCardChannelClient SmartCardChannelClient; +typedef struct SmartCardChannelClientClass SmartCardChannelClientClass; typedef struct SmartCardChannelClientPrivate SmartCardChannelClientPrivate; -struct SmartCardChannelClientPrivate { - RedCharDeviceSmartcard *smartcard; - - /* read_from_client/write_to_device buffer. - * The beginning of the buffer should always be VSCMsgHeader*/ - RedCharDeviceWriteBuffer *write_buf; - int msg_in_write_buf; /* was the client msg received into a RedCharDeviceWriteBuffer - * or was it explicitly malloced */ -}; -typedef struct SmartCardChannelClient { - RedChannelClient base; +struct SmartCardChannelClient +{ + RedChannelClient parent; - SmartCardChannelClientPrivate priv[1]; -} SmartCardChannelClient; + SmartCardChannelClientPrivate *priv; +}; + +struct SmartCardChannelClientClass +{ + RedChannelClientClass parent_class; +}; -#define SMARTCARD_CHANNEL_CLIENT(rcc) ((SmartCardChannelClient*)rcc) +GType smart_card_channel_client_get_type(void) G_GNUC_CONST; SmartCardChannelClient* smartcard_channel_client_create(RedChannel *channel, RedClient *client, RedsStream *stream, @@ -93,4 +108,6 @@ uint8_t *smartcard_channel_client_alloc_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size); +G_END_DECLS + #endif /* SMARTCARD_CHANNEL_CLIENT_H__ */ diff --git a/server/smartcard.c b/server/smartcard.c index ab952603..13eed803 100644 --- a/server/smartcard.c +++ b/server/smartcard.c @@ -500,13 +500,12 @@ static void smartcard_connect_client(RedChannel *channel, RedClient *client, SmartCardChannelClient *scc; - scc = SMARTCARD_CHANNEL_CLIENT(red_channel_client_create(sizeof(SmartCardChannelClient), - channel, - client, - stream, - FALSE, - num_common_caps, common_caps, - num_caps, caps)); + scc = smartcard_channel_client_create(channel, + client, + stream, + FALSE, + num_common_caps, common_caps, + num_caps, caps); if (!scc) { return; @@ -564,9 +563,6 @@ red_char_device_smartcard_finalize(GObject *object) RedCharDeviceSmartcard *self = RED_CHAR_DEVICE_SMARTCARD(object); free(self->priv->buf); - if (self->priv->scc) { - smartcard_channel_client_set_char_device(self->priv->scc, NULL); - } G_OBJECT_CLASS(red_char_device_smartcard_parent_class)->finalize(object); } diff --git a/server/sound.c b/server/sound.c index c08bb35a..4edf8ed3 100644 --- a/server/sound.c +++ b/server/sound.c @@ -31,6 +31,7 @@ #include "spice.h" #include "red-common.h" +#include "dummy-channel-client.h" #include "main-channel.h" #include "reds.h" #include "red-qxl.h" @@ -976,11 +977,9 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i channel->on_message_done = on_message_done; channel->cleanup = cleanup; - channel->channel_client = red_channel_client_create_dummy(sizeof(RedChannelClient), - worker->base_channel, - client, - num_common_caps, common_caps, - num_caps, caps); + channel->channel_client = + dummy_channel_client_create(worker->base_channel, client, + num_common_caps, common_caps, num_caps, caps); if (!channel->channel_client) { goto error2; } diff --git a/server/spice-server.h b/server/spice-server.h index a5c7a952..5f572f4f 100644 --- a/server/spice-server.h +++ b/server/spice-server.h @@ -72,6 +72,22 @@ int spice_server_add_interface(SpiceServer *s, */ int spice_server_remove_interface(SpiceBaseInstance *sin); +/* XXX This definition is here only to make glib generation + * of enumerators possible + */ +#if 0 +typedef enum { + SPICE_IMAGE_COMPRESSION_INVALID = 0, + SPICE_IMAGE_COMPRESSION_OFF = 1, + SPICE_IMAGE_COMPRESSION_AUTO_GLZ = 2, + SPICE_IMAGE_COMPRESSION_AUTO_LZ = 3, + SPICE_IMAGE_COMPRESSION_QUIC = 4, + SPICE_IMAGE_COMPRESSION_GLZ = 5, + SPICE_IMAGE_COMPRESSION_LZ = 6, + SPICE_IMAGE_COMPRESSION_LZ4 = 7, +} spice_image_compression_t; +#endif + // Needed for backward API compatibility typedef SpiceImageCompression spice_image_compression_t; #define SPICE_IMAGE_COMPRESS_INVALID SPICE_IMAGE_COMPRESSION_INVALID diff --git a/server/spicevmc.c b/server/spicevmc.c index 3533f3f8..e710111d 100644 --- a/server/spicevmc.c +++ b/server/spicevmc.c @@ -577,10 +577,8 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client, return; } - rcc = red_channel_client_create(sizeof(RedChannelClient), channel, client, stream, - FALSE, - num_common_caps, common_caps, - num_caps, caps); + rcc = red_channel_client_create(channel, client, stream, FALSE, + num_common_caps, common_caps, num_caps, caps); if (!rcc) { return; } |