diff options
26 files changed, 589 insertions, 1290 deletions
diff --git a/server/common-graphics-channel.cpp b/server/common-graphics-channel.cpp index 24a5d1ba..fee57166 100644 --- a/server/common-graphics-channel.cpp +++ b/server/common-graphics-channel.cpp @@ -22,8 +22,6 @@ #include "dcc.h" #include "red-client.h" -#define CHANNEL_RECEIVE_BUF_SIZE 1024 - struct CommonGraphicsChannelPrivate { int during_target_migrate; /* TRUE when the client that is associated with the channel @@ -36,43 +34,32 @@ struct CommonGraphicsChannelPrivate G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(CommonGraphicsChannel, common_graphics_channel, RED_TYPE_CHANNEL) -struct CommonGraphicsChannelClientPrivate { - uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE]; -}; - -G_DEFINE_TYPE_WITH_PRIVATE(CommonGraphicsChannelClient, common_graphics_channel_client, - RED_TYPE_CHANNEL_CLIENT) - -static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) +uint8_t *CommonGraphicsChannelClient::alloc_recv_buf(uint16_t type, uint32_t size) { - CommonGraphicsChannelClient *common = COMMON_GRAPHICS_CHANNEL_CLIENT(rcc); - /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is dynamic */ if (type == SPICE_MSGC_MIGRATE_DATA) { return (uint8_t *) g_malloc(size); } - if (size > sizeof(common->priv->recv_buf)) { - spice_warning("unexpected message size %u (max is %zd)", size, - sizeof(common->priv->recv_buf)); + if (size > sizeof(recv_buf)) { + spice_warning("unexpected message size %u (max is %zd)", size, sizeof(recv_buf)); return NULL; } - return common->priv->recv_buf; + return recv_buf; } -static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size, - uint8_t* msg) +void CommonGraphicsChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t* msg) { if (type == SPICE_MSGC_MIGRATE_DATA) { g_free(msg); } } -bool common_channel_client_config_socket(RedChannelClient *rcc) +bool CommonGraphicsChannelClient::config_socket() { - RedClient *client = rcc->get_client(); + RedClient *client = get_client(); MainChannelClient *mcc = red_client_get_main(client); - RedStream *stream = rcc->get_stream(); + RedStream *stream = get_stream(); gboolean is_low_bandwidth; // TODO - this should be dynamic, not one time at channel creation @@ -87,8 +74,8 @@ bool common_channel_client_config_socket(RedChannelClient *rcc) red_stream_set_no_delay(stream, !is_low_bandwidth); } // TODO: move wide/narrow ack setting to red_channel. - rcc->ack_set_client_window(is_low_bandwidth ? WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW); - return TRUE; + ack_set_client_window(is_low_bandwidth ? WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW); + return true; } @@ -112,20 +99,3 @@ gboolean common_graphics_channel_get_during_target_migrate(CommonGraphicsChannel { return self->priv->during_target_migrate; } - -static void -common_graphics_channel_client_init(CommonGraphicsChannelClient *self) -{ - self->priv = (CommonGraphicsChannelClientPrivate*) - common_graphics_channel_client_get_instance_private(self); -} - -static void -common_graphics_channel_client_class_init(CommonGraphicsChannelClientClass *klass) -{ - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - - client_class->config_socket = common_channel_client_config_socket; - client_class->alloc_recv_buf = common_alloc_recv_buf; - client_class->release_recv_buf = common_release_recv_buf; -} diff --git a/server/common-graphics-channel.h b/server/common-graphics-channel.h index a9d76e4c..b19f1413 100644 --- a/server/common-graphics-channel.h +++ b/server/common-graphics-channel.h @@ -25,8 +25,6 @@ G_BEGIN_DECLS -bool common_channel_client_config_socket(RedChannelClient *rcc); - #define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30) #define TYPE_COMMON_GRAPHICS_CHANNEL common_graphics_channel_get_type() @@ -65,34 +63,19 @@ enum { RED_PIPE_ITEM_TYPE_COMMON_LAST }; -#define TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT common_graphics_channel_client_get_type() - -#define COMMON_GRAPHICS_CHANNEL_CLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT, \ - CommonGraphicsChannelClient)) -#define COMMON_GRAPHICS_CHANNEL_CLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT, \ - CommonGraphicsChannelClientClass)) -#define COMMON_IS_GRAPHICS_CHANNEL_CLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT)) -#define COMMON_IS_GRAPHICS_CHANNEL_CLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT)) -#define COMMON_GRAPHICS_CHANNEL_CLIENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT, \ - CommonGraphicsChannelClientClass)) - -struct CommonGraphicsChannelClientPrivate; - -struct CommonGraphicsChannelClient: public RedChannelClient +class CommonGraphicsChannelClient: public RedChannelClient { - CommonGraphicsChannelClientPrivate *priv; -}; + enum { CHANNEL_RECEIVE_BUF_SIZE = 1024 }; + uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE]; -struct CommonGraphicsChannelClientClass { - RedChannelClientClass parent_class; -}; +public: + using RedChannelClient::RedChannelClient; -GType common_graphics_channel_client_get_type(void) G_GNUC_CONST; +protected: + virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size) override; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) override; + virtual bool config_socket() override; +}; G_END_DECLS diff --git a/server/cursor-channel-client.cpp b/server/cursor-channel-client.cpp index dd64580c..15600b7f 100644 --- a/server/cursor-channel-client.cpp +++ b/server/cursor-channel-client.cpp @@ -35,32 +35,13 @@ struct CursorChannelClientPrivate { + SPICE_CXX_GLIB_ALLOCATOR + RedCacheItem *cursor_cache[CURSOR_CACHE_HASH_SIZE]; - Ring cursor_cache_lru; - long cursor_cache_available; + Ring cursor_cache_lru = { nullptr, nullptr }; + long cursor_cache_available = 0; }; -G_DEFINE_TYPE_WITH_PRIVATE(CursorChannelClient, cursor_channel_client, - TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT) - -static void cursor_channel_client_on_disconnect(RedChannelClient *rcc); - -static void -cursor_channel_client_class_init(CursorChannelClientClass *klass) -{ - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - - client_class->on_disconnect = cursor_channel_client_on_disconnect; -} - -static void -cursor_channel_client_init(CursorChannelClient *self) -{ - self->priv = (CursorChannelClientPrivate*) cursor_channel_client_get_instance_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.cpp" #undef CLIENT_CURSOR_CACHE @@ -74,12 +55,9 @@ void cursor_channel_client_reset_cursor_cache(CursorChannelClient *ccc) red_cursor_cache_reset(ccc, CLIENT_CURSOR_CACHE_SIZE); } -static void cursor_channel_client_on_disconnect(RedChannelClient *rcc) +void CursorChannelClient::on_disconnect() { - if (!rcc) { - return; - } - cursor_channel_client_reset_cursor_cache(CURSOR_CHANNEL_CLIENT(rcc)); + cursor_channel_client_reset_cursor_cache(this); } void cursor_channel_client_migrate(RedChannelClient *rcc) @@ -90,20 +68,32 @@ void cursor_channel_client_migrate(RedChannelClient *rcc) RedChannelClient::default_migrate(rcc); } +CursorChannelClient::CursorChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps): + CommonGraphicsChannelClient(channel, client, stream, caps) +{ + priv = new CursorChannelClientPrivate(); + ring_init(&priv->cursor_cache_lru); + priv->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE; +} + +CursorChannelClient::~CursorChannelClient() +{ + delete priv; +} + CursorChannelClient* cursor_channel_client_new(CursorChannel *cursor, RedClient *client, RedStream *stream, int mig_target, RedChannelCapabilities *caps) { - CursorChannelClient *rcc; - - rcc = (CursorChannelClient*) - g_initable_new(TYPE_CURSOR_CHANNEL_CLIENT, - NULL, NULL, - "channel", cursor, - "client", client, - "stream", stream, - "caps", caps, - NULL); + auto rcc = new CursorChannelClient(RED_CHANNEL(cursor), client, stream, caps); + + if (!rcc->init()) { + rcc->unref(); + rcc = nullptr; + } common_graphics_channel_set_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor), mig_target); return rcc; diff --git a/server/cursor-channel-client.h b/server/cursor-channel-client.h index 5688f1f3..38f22530 100644 --- a/server/cursor-channel-client.h +++ b/server/cursor-channel-client.h @@ -19,8 +19,6 @@ #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-client.h" @@ -29,33 +27,21 @@ 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)) - struct CursorChannelClientPrivate; -struct CursorChannelClient final: public CommonGraphicsChannelClient +class CursorChannelClient final: public CommonGraphicsChannelClient { - CursorChannelClientPrivate *priv; +protected: + ~CursorChannelClient(); +public: + CursorChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps); + virtual void on_disconnect() override; + CursorChannelClientPrivate *priv = nullptr; }; -struct CursorChannelClientClass -{ - RedChannelClientClass parent_class; -}; - -GType cursor_channel_client_get_type(void) G_GNUC_CONST; - CursorChannelClient* cursor_channel_client_new(CursorChannel *cursor, RedClient *client, RedStream *stream, diff --git a/server/cursor-channel.cpp b/server/cursor-channel.cpp index b084ef72..ba44ff55 100644 --- a/server/cursor-channel.cpp +++ b/server/cursor-channel.cpp @@ -193,6 +193,8 @@ static inline void red_marshall_inval(RedChannelClient *rcc, spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one); } +XXX_CAST(RedChannelClient, CursorChannelClient, CURSOR_CHANNEL_CLIENT); + static void cursor_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item) { SpiceMarshaller *m = rcc->get_marshaller(); @@ -211,7 +213,7 @@ static void cursor_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_it break; case RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE: cursor_channel_client_reset_cursor_cache(ccc); - rcc->init_send_data(SPICE_MSG_CURSOR_INVAL_ALL); + ccc->init_send_data(SPICE_MSG_CURSOR_INVAL_ALL); break; default: spice_error("invalid pipe item type"); diff --git a/server/dcc-private.h b/server/dcc-private.h index c171d999..13b1b660 100644 --- a/server/dcc-private.h +++ b/server/dcc-private.h @@ -27,22 +27,24 @@ struct DisplayChannelClientPrivate { - uint32_t id; + SPICE_CXX_GLIB_ALLOCATOR + + uint32_t id = 0; SpiceImageCompression image_compression; spice_wan_compression_t jpeg_state; spice_wan_compression_t zlib_glz_state; ImageEncoders encoders; - int expect_init; + int expect_init = 0; - PixmapCache *pixmap_cache; - uint32_t pixmap_cache_generation; - int pending_pixmaps_sync; + PixmapCache *pixmap_cache = nullptr; + uint32_t pixmap_cache_generation = 0; + int pending_pixmaps_sync = 0; RedCacheItem *palette_cache[PALETTE_CACHE_HASH_SIZE]; - Ring palette_cache_lru; - long palette_cache_available; + Ring palette_cache_lru = { nullptr, nullptr }; + long palette_cache_available = CLIENT_PALETTE_CACHE_SIZE; struct { FreeList free_list; diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp index 3cde9710..2b0fd319 100644 --- a/server/dcc-send.cpp +++ b/server/dcc-send.cpp @@ -24,6 +24,9 @@ #include "display-channel-private.h" #include "red-qxl.h" +// XXX this should go away with virtual on the right class (client!) +XXX_CAST(RedChannelClient, DisplayChannelClient, DISPLAY_CHANNEL_CLIENT) + typedef enum { FILL_BITS_TYPE_INVALID, FILL_BITS_TYPE_CACHE, diff --git a/server/dcc.cpp b/server/dcc.cpp index d9ac0047..6173fd1c 100644 --- a/server/dcc.cpp +++ b/server/dcc.cpp @@ -25,157 +25,50 @@ #include "main-channel-client.h" #include <spice-server-enums.h> -G_DEFINE_TYPE(DisplayChannelClient, display_channel_client, TYPE_COMMON_GRAPHICS_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 bool dcc_config_socket(RedChannelClient *rcc); -static void dcc_on_disconnect(RedChannelClient *rcc); - -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 = (SpiceImageCompression) g_value_get_enum(value); - break; - case PROP_JPEG_STATE: - self->priv->jpeg_state = (spice_wan_compression_t) g_value_get_enum(value); - break; - case PROP_ZLIB_GLZ_STATE: - self->priv->zlib_glz_state = (spice_wan_compression_t) 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::DisplayChannelClient(DisplayChannel *display, + RedClient *client, RedStream *stream, + RedChannelCapabilities *caps, + uint32_t id, + SpiceImageCompression image_compression, + spice_wan_compression_t jpeg_state, + spice_wan_compression_t zlib_glz_state): + CommonGraphicsChannelClient(RED_CHANNEL(display), client, stream, caps, true) { - DisplayChannelClient *self = DISPLAY_CHANNEL_CLIENT(object); + priv = new DisplayChannelClientPrivate; - G_OBJECT_CLASS(display_channel_client_parent_class)->constructed(object); + // XXX from display_channel_client_init, put somewhere else + ring_init(&priv->palette_cache_lru); + // todo: tune quality according to bandwidth + priv->encoders.jpeg_quality = 85; - dcc_init_stream_agents(self); + priv->send_data.free_list.res = (SpiceResourceList*) + g_malloc(sizeof(SpiceResourceList) + + DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID)); + priv->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE; - 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); + priv->image_compression = image_compression; + priv->jpeg_state = jpeg_state; + priv->zlib_glz_state = zlib_glz_state; - g_clear_pointer(&self->priv->preferred_video_codecs, g_array_unref); - g_clear_pointer(&self->priv->client_preferred_video_codecs, g_array_unref); - g_free(self->priv); - G_OBJECT_CLASS(display_channel_client_parent_class)->finalize(object); -} + priv->id = id; -static void -display_channel_client_class_init(DisplayChannelClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_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; - - client_class->config_socket = dcc_config_socket; - client_class->on_disconnect = dcc_on_disconnect; - - 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)); + image_encoders_init(&priv->encoders, &DCC_TO_DC(this)->priv->encoder_shared_data); + + dcc_init_stream_agents(this); } -static void display_channel_client_init(DisplayChannelClient *self) +DisplayChannelClient::~DisplayChannelClient() { - /* 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 = (SpiceResourceList*) - g_malloc(sizeof(SpiceResourceList) + - DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID)); - self->priv->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE; + g_clear_pointer(&priv->preferred_video_codecs, g_array_unref); + g_clear_pointer(&priv->client_preferred_video_codecs, g_array_unref); + g_free(priv); } static RedSurfaceCreateItem *red_surface_create_item_new(RedChannel* channel, @@ -491,25 +384,15 @@ DisplayChannelClient *dcc_new(DisplayChannel *display, spice_wan_compression_t zlib_glz_state) { - DisplayChannelClient *dcc; - - dcc = (DisplayChannelClient*) - g_initable_new(TYPE_DISPLAY_CHANNEL_CLIENT, - NULL, NULL, - "channel", display, - "client", client, - "stream", stream, - "monitor-latency", TRUE, - "caps", caps, - "image-compression", image_compression, - "jpeg-state", jpeg_state, - "zlib-glz-state", zlib_glz_state, - NULL); + auto dcc = + new DisplayChannelClient(display, client, stream, caps, display->priv->qxl->id, + image_compression, jpeg_state, zlib_glz_state); + if (!dcc->init()) { + dcc->unref(); + dcc = nullptr; + } spice_debug("New display (client %p) dcc %p stream %p", client, dcc, stream); common_graphics_channel_set_during_target_migrate(display, mig_target); - if (dcc) { - dcc->priv->id = display->priv->qxl->id; - } return dcc; } @@ -695,6 +578,8 @@ RedPipeItem *dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num) return &item->base; } +XXX_CAST(RedChannelClient, DisplayChannelClient, DISPLAY_CHANNEL_CLIENT); + RedPipeItem *dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num) { DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc); @@ -1374,28 +1259,25 @@ void dcc_set_max_stream_bit_rate(DisplayChannelClient *dcc, uint64_t rate) dcc->priv->streams_max_bit_rate = rate; } -static bool dcc_config_socket(RedChannelClient *rcc) +bool DisplayChannelClient::config_socket() { - RedClient *client = rcc->get_client(); + RedClient *client = get_client(); MainChannelClient *mcc = red_client_get_main(client); - DISPLAY_CHANNEL_CLIENT(rcc)->is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc); + is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc); - return common_channel_client_config_socket(rcc); + return CommonGraphicsChannelClient::config_socket(); } -static void dcc_on_disconnect(RedChannelClient *rcc) +void DisplayChannelClient::on_disconnect() { DisplayChannel *display; - DisplayChannelClient *dcc; spice_debug("trace"); - spice_return_if_fail(rcc != NULL); - dcc = DISPLAY_CHANNEL_CLIENT(rcc); - display = DCC_TO_DC(dcc); + display = DCC_TO_DC(this); - dcc_stop(dcc); // TODO: start/stop -> connect/disconnect? + dcc_stop(this); // TODO: start/stop -> connect/disconnect? display_channel_compress_stats_print(display); // this was the last channel client diff --git a/server/dcc.h b/server/dcc.h index 740829b1..3974d284 100644 --- a/server/dcc.h +++ b/server/dcc.h @@ -19,8 +19,6 @@ #ifndef DCC_H_ #define DCC_H_ -#include <glib-object.h> - #include "image-encoders.h" #include "image-cache.h" #include "pixmap-cache.h" @@ -29,34 +27,30 @@ 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)) - +struct DisplayChannel; struct DisplayChannelClientPrivate; -struct DisplayChannelClient final: public CommonGraphicsChannelClient +class DisplayChannelClient final: public CommonGraphicsChannelClient { - int is_low_bandwidth; +protected: + ~DisplayChannelClient(); +public: + DisplayChannelClient(DisplayChannel *display, + RedClient *client, RedStream *stream, + RedChannelCapabilities *caps, + uint32_t id, + SpiceImageCompression image_compression, + spice_wan_compression_t jpeg_state, + spice_wan_compression_t zlib_glz_state); + + virtual bool config_socket() override; + virtual void on_disconnect() override; + + DisplayChannelClientPrivate *priv = nullptr; - DisplayChannelClientPrivate *priv; -}; - -struct DisplayChannelClientClass { - CommonGraphicsChannelClientClass parent_class; + int is_low_bandwidth; }; -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) diff --git a/server/display-channel.cpp b/server/display-channel.cpp index 339a1a39..91d5829c 100644 --- a/server/display-channel.cpp +++ b/server/display-channel.cpp @@ -21,6 +21,8 @@ #include "display-channel-private.h" #include "red-qxl.h" +XXX_CAST(RedChannelClient, DisplayChannelClient, DISPLAY_CHANNEL_CLIENT); + G_DEFINE_TYPE(DisplayChannel, display_channel, TYPE_COMMON_GRAPHICS_CHANNEL) static void display_channel_connect(RedChannel *channel, RedClient *client, diff --git a/server/inputs-channel-client.cpp b/server/inputs-channel-client.cpp index b55b4d8b..71e1f1c3 100644 --- a/server/inputs-channel-client.cpp +++ b/server/inputs-channel-client.cpp @@ -20,68 +20,25 @@ #include "migration-protocol.h" #include "red-channel-client.h" -// TODO: RECEIVE_BUF_SIZE used to be the same for inputs_channel and main_channel -// since it was defined once in reds.c which contained both. -// Now that they are split we can give a more fitting value for inputs - what -// should it be? -#define REDS_AGENT_WINDOW_SIZE 10 -#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1 - -// approximate max receive message size -#define RECEIVE_BUF_SIZE \ - (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE) - -struct InputsChannelClientPrivate -{ - uint16_t motion_count; - uint8_t recv_buf[RECEIVE_BUF_SIZE]; -}; - -G_DEFINE_TYPE_WITH_PRIVATE(InputsChannelClient, inputs_channel_client, RED_TYPE_CHANNEL_CLIENT) +XXX_CAST(RedChannelClient, InputsChannelClient, INPUTS_CHANNEL_CLIENT); -static uint8_t * -inputs_channel_client_alloc_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size) +uint8_t *InputsChannelClient::alloc_recv_buf(uint16_t type, uint32_t size) { - InputsChannelClient *icc = INPUTS_CHANNEL_CLIENT(rcc); - - if (size > sizeof(icc->priv->recv_buf)) { - red_channel_warning(rcc->get_channel(), - "error: too large incoming message"); + if (size > sizeof(recv_buf)) { + red_channel_warning(get_channel(), "error: too large incoming message"); return NULL; } - return icc->priv->recv_buf; + return recv_buf; } -static void -inputs_channel_client_release_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size, uint8_t *msg) +void InputsChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) { } -static void inputs_channel_client_on_disconnect(RedChannelClient *rcc) +void InputsChannelClient::on_disconnect() { - if (!rcc) { - return; - } - inputs_release_keys(INPUTS_CHANNEL(rcc->get_channel())); -} - -static void -inputs_channel_client_class_init(InputsChannelClientClass *klass) -{ - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - - client_class->alloc_recv_buf = inputs_channel_client_alloc_msg_rcv_buf; - client_class->release_recv_buf = inputs_channel_client_release_msg_rcv_buf; - client_class->on_disconnect = inputs_channel_client_on_disconnect; -} - -static void -inputs_channel_client_init(InputsChannelClient *self) -{ - self->priv = (InputsChannelClientPrivate *) inputs_channel_client_get_instance_private(self); + inputs_release_keys(INPUTS_CHANNEL(get_channel())); } RedChannelClient* inputs_channel_client_create(RedChannel *channel, @@ -89,17 +46,11 @@ RedChannelClient* inputs_channel_client_create(RedChannel *channel, RedStream *stream, RedChannelCapabilities *caps) { - RedChannelClient *rcc; - - rcc = (RedChannelClient *) - g_initable_new(TYPE_INPUTS_CHANNEL_CLIENT, - NULL, NULL, - "channel", channel, - "client", client, - "stream", stream, - "caps", caps, - NULL); - + auto rcc = new InputsChannelClient(channel, client, stream, caps); + if (!rcc->init()) { + delete rcc; + rcc = nullptr; + } return rcc; } @@ -113,16 +64,16 @@ void inputs_channel_client_send_migrate_data(RedChannelClient *rcc, spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_INPUTS_MAGIC); spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_INPUTS_VERSION); - spice_marshaller_add_uint16(m, icc->priv->motion_count); + spice_marshaller_add_uint16(m, icc->motion_count); } void inputs_channel_client_handle_migrate_data(InputsChannelClient *icc, uint16_t motion_count) { - icc->priv->motion_count = motion_count; + icc->motion_count = motion_count; - for (; icc->priv->motion_count >= SPICE_INPUT_MOTION_ACK_BUNCH; - icc->priv->motion_count -= SPICE_INPUT_MOTION_ACK_BUNCH) { + for (; icc->motion_count >= SPICE_INPUT_MOTION_ACK_BUNCH; + icc->motion_count -= SPICE_INPUT_MOTION_ACK_BUNCH) { icc->pipe_add_type(RED_PIPE_ITEM_MOUSE_MOTION_ACK); } } @@ -131,9 +82,9 @@ void inputs_channel_client_on_mouse_motion(InputsChannelClient *icc) { InputsChannel *inputs_channel = INPUTS_CHANNEL(icc->get_channel()); - if (++icc->priv->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0 && + if (++icc->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0 && !inputs_channel_is_src_during_migrate(inputs_channel)) { icc->pipe_add_type(RED_PIPE_ITEM_MOUSE_MOTION_ACK); - icc->priv->motion_count = 0; + icc->motion_count = 0; } } diff --git a/server/inputs-channel-client.h b/server/inputs-channel-client.h index 4d979a05..141383b2 100644 --- a/server/inputs-channel-client.h +++ b/server/inputs-channel-client.h @@ -18,31 +18,34 @@ #ifndef INPUTS_CHANNEL_CLIENT_H_ #define INPUTS_CHANNEL_CLIENT_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)) +// TODO: RECEIVE_BUF_SIZE used to be the same for inputs_channel and main_channel +// since it was defined once in reds.c which contained both. +// Now that they are split we can give a more fitting value for inputs - what +// should it be? +#define REDS_AGENT_WINDOW_SIZE 10 +#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1 -struct InputsChannelClientPrivate; +// approximate max receive message size +#define RECEIVE_BUF_SIZE \ + (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE) -struct InputsChannelClient final: public RedChannelClient +class InputsChannelClient final: public RedChannelClient { - InputsChannelClientPrivate *priv; -}; + uint8_t recv_buf[RECEIVE_BUF_SIZE]; +public: + uint16_t motion_count; // XXX private -struct InputsChannelClientClass -{ - RedChannelClientClass parent_class; -}; + using RedChannelClient::RedChannelClient; -GType inputs_channel_client_get_type(void) G_GNUC_CONST; + virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size) override; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) override; + virtual void on_disconnect() override; +}; RedChannelClient* inputs_channel_client_create(RedChannel *channel, RedClient *client, diff --git a/server/inputs-channel.cpp b/server/inputs-channel.cpp index 67ead1db..9199eead 100644 --- a/server/inputs-channel.cpp +++ b/server/inputs-channel.cpp @@ -40,6 +40,8 @@ #include "migration-protocol.h" #include "utils.h" +XXX_CAST(RedChannelClient, InputsChannelClient, INPUTS_CHANNEL_CLIENT); + struct InputsChannel final: public RedChannel { VDAgentMouseState mouse_state; diff --git a/server/main-channel-client.cpp b/server/main-channel-client.cpp index f5e7c643..3d8cf6b6 100644 --- a/server/main-channel-client.cpp +++ b/server/main-channel-client.cpp @@ -43,24 +43,24 @@ typedef enum { (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE) struct MainChannelClientPrivate { + SPICE_CXX_GLIB_ALLOCATOR + uint32_t connection_id; - uint32_t ping_id; - uint32_t net_test_id; - NetTestStage net_test_stage; - uint64_t latency; - uint64_t bitrate_per_sec; - int mig_wait_connect; - int mig_connect_ok; - int mig_wait_prev_complete; - int mig_wait_prev_try_seamless; - int init_sent; - int seamless_mig_dst; - bool initial_channels_list_sent; + uint32_t ping_id = 0; + uint32_t net_test_id = 0; + NetTestStage net_test_stage = NET_TEST_STAGE_INVALID; + uint64_t latency = 0; + uint64_t bitrate_per_sec = ~0; + int mig_wait_connect = 0; + int mig_connect_ok = 0; + int mig_wait_prev_complete = 0; + int mig_wait_prev_try_seamless = 0; + int init_sent = 0; + int seamless_mig_dst = 0; + bool initial_channels_list_sent = false; uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE]; }; -G_DEFINE_TYPE_WITH_PRIVATE(MainChannelClient, main_channel_client, RED_TYPE_CHANNEL_CLIENT) - typedef struct RedPingPipeItem { RedPipeItem base; int size; @@ -125,68 +125,23 @@ typedef struct RedRegisteredChannelPipeItem { 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 uint8_t * -main_channel_client_alloc_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size) +uint8_t *MainChannelClient::alloc_recv_buf(uint16_t type, uint32_t size) { - MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc); - if (type == SPICE_MSGC_MAIN_AGENT_DATA) { - RedChannel *channel = rcc->get_channel(); - return reds_get_agent_data_buffer(channel->get_server(), mcc, size); - } else if (size > sizeof(mcc->priv->recv_buf)) { + RedChannel *channel = get_channel(); + return reds_get_agent_data_buffer(channel->get_server(), this, size); + } else if (size > sizeof(priv->recv_buf)) { /* message too large, caller will log a message and close the connection */ return NULL; } else { - return mcc->priv->recv_buf; + return priv->recv_buf; } } -static void -main_channel_client_release_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size, uint8_t *msg) +void MainChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) { if (type == SPICE_MSGC_MAIN_AGENT_DATA) { - RedChannel *channel = rcc->get_channel(); + RedChannel *channel = get_channel(); reds_release_agent_data_buffer(channel->get_server(), msg); } } @@ -194,42 +149,11 @@ main_channel_client_release_msg_rcv_buf(RedChannelClient *rcc, /* * When the main channel is disconnected, disconnect the entire client. */ -static void main_channel_client_on_disconnect(RedChannelClient *rcc) +void MainChannelClient::on_disconnect() { - RedsState *reds = rcc->get_channel()->get_server(); + RedsState *reds = get_channel()->get_server(); main_dispatcher_client_disconnect(reds_get_main_dispatcher(reds), - rcc->get_client()); -} - -static void main_channel_client_class_init(MainChannelClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - - object_class->get_property = main_channel_client_get_property; - object_class->set_property = main_channel_client_set_property; - - client_class->alloc_recv_buf = main_channel_client_alloc_msg_rcv_buf; - client_class->release_recv_buf = main_channel_client_release_msg_rcv_buf; - client_class->on_disconnect = main_channel_client_on_disconnect; - - 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 = (MainChannelClientPrivate *) main_channel_client_get_instance_private(self); - self->priv->bitrate_per_sec = ~0; + get_client()); } static void main_channel_client_push_ping(MainChannelClient *mcc, int size); @@ -602,22 +526,32 @@ gboolean main_channel_client_migrate_src_complete(MainChannelClient *mcc, return ret; } + +MainChannelClient::MainChannelClient(MainChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps, + uint32_t connection_id): + RedChannelClient(RED_CHANNEL(channel), client, stream, caps), + priv(new MainChannelClientPrivate()) +{ + priv->connection_id = connection_id; +} + +MainChannelClient::~MainChannelClient() +{ + delete priv; +} + MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient *client, RedStream *stream, uint32_t connection_id, RedChannelCapabilities *caps) { - MainChannelClient *mcc; - - mcc = (MainChannelClient *) - g_initable_new(TYPE_MAIN_CHANNEL_CLIENT, - NULL, NULL, - "channel", main_chan, - "client", client, - "stream", stream, - "caps", caps, - "connection-id", connection_id, - NULL); - + auto mcc = new MainChannelClient(main_chan, client, stream, caps, connection_id); + if (!mcc->init()) { + mcc->unref(); + mcc = nullptr; + } return mcc; } @@ -642,6 +576,8 @@ uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc) return mcc->priv->latency / 1000; } +XXX_CAST(RedChannelClient, MainChannelClient, MAIN_CHANNEL_CLIENT); + void main_channel_client_migrate(RedChannelClient *rcc) { RedChannel *channel = rcc->get_channel(); diff --git a/server/main-channel-client.h b/server/main-channel-client.h index 2090b596..7653978d 100644 --- a/server/main-channel-client.h +++ b/server/main-channel-client.h @@ -18,7 +18,6 @@ #ifndef MAIN_CHANNEL_CLIENT_H_ #define MAIN_CHANNEL_CLIENT_H_ -#include <glib-object.h> #include <common/messages.h> #include "red-channel-client.h" @@ -26,33 +25,25 @@ G_BEGIN_DECLS -#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)) - struct MainChannelClientPrivate; -struct MainChannelClient final: public RedChannelClient -{ - MainChannelClientPrivate *priv; -}; - -struct MainChannelClientClass +class MainChannelClient final: public RedChannelClient { - RedChannelClientClass parent_class; +protected: + ~MainChannelClient(); +public: + MainChannelClient(MainChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps, + uint32_t connection_id); + + virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size) override; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) override; + virtual void on_disconnect() override; + MainChannelClientPrivate *const priv = nullptr; }; -GType main_channel_client_get_type(void) G_GNUC_CONST; - MainChannelClient *main_channel_client_create(MainChannel *main_chan, RedClient *client, RedStream *stream, uint32_t connection_id, RedChannelCapabilities *caps); diff --git a/server/main-channel.cpp b/server/main-channel.cpp index f867254f..8764cc84 100644 --- a/server/main-channel.cpp +++ b/server/main-channel.cpp @@ -45,6 +45,8 @@ int main_channel_is_connected(MainChannel *main_chan) return main_chan && main_chan->is_connected(); } +XXX_CAST(RedChannelClient, MainChannelClient, MAIN_CHANNEL_CLIENT); + RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t connection_id) { RedChannelClient *rcc; diff --git a/server/red-channel-client.cpp b/server/red-channel-client.cpp index b60b89d8..5b10a7ff 100644 --- a/server/red-channel-client.cpp +++ b/server/red-channel-client.cpp @@ -115,6 +115,8 @@ typedef struct IncomingMessageBuffer { struct RedChannelClientPrivate { + SPICE_CXX_GLIB_ALLOCATOR + RedChannel *channel; RedClient *client; RedStream *stream; @@ -196,9 +198,7 @@ static const SpiceDataHeaderOpaque mini_header_wrapper = {NULL, sizeof(SpiceMini mini_header_get_msg_size}; static void red_channel_client_clear_sent_item(RedChannelClient *rcc); -static void red_channel_client_initable_interface_init(GInitableIface *iface); static void red_channel_client_set_message_serial(RedChannelClient *channel, uint64_t); -static bool red_channel_client_config_socket(RedChannelClient *rcc); /* * When an error occurs over a channel, we treat it as a warning @@ -210,24 +210,6 @@ static bool red_channel_client_config_socket(RedChannelClient *rcc); rcc->shutdown(); \ } while (0) -G_DEFINE_TYPE_WITH_CODE(RedChannelClient, red_channel_client, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, - red_channel_client_initable_interface_init); - G_ADD_PRIVATE(RedChannelClient)); - -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_CAPS -}; - #define PING_TEST_TIMEOUT_MS (MSEC_PER_SEC * 15) #define PING_TEST_LONG_TIMEOUT_MS (MSEC_PER_SEC * 60 * 5) #define PING_TEST_IDLE_NET_TIMEOUT_MS (MSEC_PER_SEC / 10) @@ -284,112 +266,60 @@ 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::~RedChannelClient() { - RedChannelClient *self = RED_CHANNEL_CLIENT(object); + red_timer_remove(priv->latency_monitor.timer); + priv->latency_monitor.timer = NULL; - switch (property_id) - { - case PROP_STREAM: - g_value_set_pointer(value, self->priv->stream); - break; - case PROP_CHANNEL: - g_value_set_object(value, self->priv->channel); - break; - case PROP_CLIENT: - g_value_set_object(value, self->priv->client); - break; - case PROP_MONITOR_LATENCY: - g_value_set_boolean(value, self->priv->monitor_latency); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + red_timer_remove(priv->connectivity_monitor.timer); + priv->connectivity_monitor.timer = NULL; + + red_stream_free(priv->stream); + priv->stream = NULL; + + if (priv->send_data.main.marshaller) { + spice_marshaller_destroy(priv->send_data.main.marshaller); } -} -static void -red_channel_client_set_property(GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - RedChannelClient *self = RED_CHANNEL_CLIENT(object); + if (priv->send_data.urgent.marshaller) { + spice_marshaller_destroy(priv->send_data.urgent.marshaller); + } - switch (property_id) - { - case PROP_STREAM: - self->priv->stream = (RedStream*) g_value_get_pointer(value); - break; - case PROP_CHANNEL: - if (self->priv->channel) - g_object_unref(self->priv->channel); - self->priv->channel = (RedChannel *) g_value_dup_object(value); - break; - case PROP_CLIENT: - self->priv->client = (RedClient *) g_value_get_object(value); - break; - case PROP_MONITOR_LATENCY: - self->priv->monitor_latency = g_value_get_boolean(value); - break; - case PROP_CAPS: - { - RedChannelCapabilities *caps = (RedChannelCapabilities *) g_value_get_boxed(value); - if (caps) { - red_channel_capabilities_reset(&self->priv->remote_caps); - red_channel_capabilities_init(&self->priv->remote_caps, caps); - } - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + red_channel_capabilities_reset(&priv->remote_caps); + if (priv->channel) { + g_object_unref(priv->channel); } + delete priv; } -static void -red_channel_client_finalize(GObject *object) +RedChannelClient::RedChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps, + bool monitor_latency) { - RedChannelClient *self = RED_CHANNEL_CLIENT(object); - - red_timer_remove(self->priv->latency_monitor.timer); - self->priv->latency_monitor.timer = NULL; + RedChannelClient *self = this; - red_timer_remove(self->priv->connectivity_monitor.timer); - self->priv->connectivity_monitor.timer = NULL; + // XXX initialize + priv = new RedChannelClientPrivate(); - red_stream_free(self->priv->stream); - self->priv->stream = NULL; + // 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(); - if (self->priv->send_data.main.marshaller) { - spice_marshaller_destroy(self->priv->send_data.main.marshaller); - } + self->priv->send_data.marshaller = self->priv->send_data.main.marshaller; - if (self->priv->send_data.urgent.marshaller) { - spice_marshaller_destroy(self->priv->send_data.urgent.marshaller); - } + g_queue_init(&self->priv->pipe); red_channel_capabilities_reset(&self->priv->remote_caps); - if (self->priv->channel) { - g_object_unref(self->priv->channel); - } + red_channel_capabilities_init(&self->priv->remote_caps, caps); - 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 void red_channel_client_constructed(GObject *object) -{ - RedChannelClient *self = RED_CHANNEL_CLIENT(object); - - RedChannelClientClass *klass = RED_CHANNEL_CLIENT_GET_CLASS(self); - spice_assert(klass->alloc_recv_buf && klass->release_recv_buf); + priv->channel = (RedChannel*) g_object_ref(channel); + priv->client = client; + priv->stream = stream; self->priv->outgoing.pos = 0; self->priv->outgoing.size = 0; @@ -405,81 +335,12 @@ static void red_channel_client_constructed(GObject *object) } self->priv->incoming.header.data = self->priv->incoming.header_buf; - RedChannel *channel = self->priv->channel; RedsState* reds = channel->get_server(); const RedStatNode *node = channel->get_stat_node(); stat_init_counter(&self->priv->out_messages, reds, node, "out_messages", TRUE); stat_init_counter(&self->priv->out_bytes, reds, node, "out_bytes", TRUE); } -static void red_channel_client_class_init(RedChannelClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GParamSpec *spec; - - g_debug("%s", G_STRFUNC); - - 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; - - 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_object("channel", "channel", - "Associated RedChannel", - RED_TYPE_CHANNEL, - 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_object("client", "client", - "Associated RedClient", - RED_TYPE_CLIENT, - 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("caps", "caps", - "Capabilities", - RED_TYPE_CHANNEL_CAPABILITIES, - G_PARAM_STATIC_STRINGS - | G_PARAM_WRITABLE - | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property(object_class, PROP_CAPS, spec); -} - -static void -red_channel_client_init(RedChannelClient *self) -{ - self->priv = (RedChannelClientPrivate *) red_channel_client_get_instance_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; - - g_queue_init(&self->priv->pipe); -} - RedChannel* RedChannelClient::get_channel() { return priv->channel; @@ -912,13 +773,11 @@ static void mini_header_set_msg_sub_list(SpiceDataHeaderOpaque *header, uint32_t spice_error("attempt to set header sub list on mini header"); } -static gboolean red_channel_client_initable_init(GInitable *initable, - GCancellable *cancellable, - GError **error) +bool RedChannelClient::init() { GError *local_error = NULL; SpiceCoreInterfaceInternal *core; - RedChannelClient *self = RED_CHANNEL_CLIENT(initable); + RedChannelClient *self = this; if (!self->priv->stream) { g_set_error_literal(&local_error, @@ -928,7 +787,7 @@ static gboolean red_channel_client_initable_init(GInitable *initable, goto cleanup; } - if (!red_channel_client_config_socket(self)) { + if (!self->config_socket()) { g_set_error_literal(&local_error, SPICE_SERVER_ERROR, SPICE_SERVER_ERROR_FAILED, @@ -967,7 +826,7 @@ cleanup: red_channel_warning(self->get_channel(), "Failed to create channel client: %s", local_error->message); - g_propagate_error(error, local_error); + g_error_free(local_error); } return local_error == NULL; } @@ -1048,34 +907,6 @@ void RedChannelClient::shutdown() } } -static bool red_channel_client_config_socket(RedChannelClient *rcc) -{ - RedChannelClientClass *klass = RED_CHANNEL_CLIENT_GET_CLASS(rcc); - - if (!klass->config_socket) { - return TRUE; - } - - return klass->config_socket(rcc); -} - -static uint8_t *red_channel_client_alloc_msg_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size) -{ - RedChannelClientClass *klass = RED_CHANNEL_CLIENT_GET_CLASS(rcc); - - return klass->alloc_recv_buf(rcc, type, size); -} - -static void red_channel_client_release_msg_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size, - uint8_t *msg) -{ - RedChannelClientClass *klass = RED_CHANNEL_CLIENT_GET_CLASS(rcc); - - klass->release_recv_buf(rcc, type, size, msg); -} - static void red_channel_client_handle_outgoing(RedChannelClient *rcc) { RedStream *stream = rcc->priv->stream; @@ -1221,7 +1052,7 @@ static void red_channel_client_handle_incoming(RedChannelClient *rcc) msg_type = buffer->header.get_msg_type(&buffer->header); if (buffer->msg_pos < msg_size) { if (!buffer->msg) { - buffer->msg = red_channel_client_alloc_msg_buf(rcc, msg_type, msg_size); + buffer->msg = rcc->alloc_recv_buf(msg_type, msg_size); if (buffer->msg == NULL && rcc->priv->block_read) { // if we are blocked by flow control just return, message will be read // when data will be available @@ -1238,8 +1069,7 @@ static void red_channel_client_handle_incoming(RedChannelClient *rcc) buffer->msg + buffer->msg_pos, msg_size - buffer->msg_pos); if (bytes_read == -1) { - red_channel_client_release_msg_buf(rcc, msg_type, msg_size, - buffer->msg); + rcc->release_recv_buf(msg_type, msg_size, buffer->msg); buffer->msg = NULL; rcc->disconnect(); return; @@ -1257,9 +1087,7 @@ static void red_channel_client_handle_incoming(RedChannelClient *rcc) &parsed_size, &parsed_free); if (parsed == NULL) { red_channel_warning(channel, "failed to parse message type %d", msg_type); - red_channel_client_release_msg_buf(rcc, - msg_type, msg_size, - buffer->msg); + rcc->release_recv_buf(msg_type, msg_size, buffer->msg); buffer->msg = NULL; rcc->disconnect(); return; @@ -1270,9 +1098,7 @@ static void red_channel_client_handle_incoming(RedChannelClient *rcc) parsed_free(parsed); } buffer->msg_pos = 0; - red_channel_client_release_msg_buf(rcc, - msg_type, msg_size, - buffer->msg); + rcc->release_recv_buf(msg_type, msg_size, buffer->msg); buffer->msg = NULL; buffer->header_pos = 0; @@ -1711,15 +1537,6 @@ void RedChannelClient::push_set_ack() pipe_add_type(RED_PIPE_ITEM_TYPE_SET_ACK); } -static void red_channel_client_on_disconnect(RedChannelClient *rcc) -{ - RedChannelClientClass *klass = RED_CHANNEL_CLIENT_GET_CLASS(rcc); - - if (klass->on_disconnect != NULL) { - klass->on_disconnect(rcc); - } -} - void RedChannelClient::disconnect() { RedChannel *channel = priv->channel; @@ -1738,7 +1555,7 @@ void RedChannelClient::disconnect() priv->connectivity_monitor.timer = NULL; channel->remove_client(this); - red_channel_client_on_disconnect(this); + on_disconnect(); // remove client from RedClient // NOTE this may trigger the free of the object, if we are in a watch/timer // we should make sure we keep a reference diff --git a/server/red-channel-client.h b/server/red-channel-client.h index 102074ec..d38cad60 100644 --- a/server/red-channel-client.h +++ b/server/red-channel-client.h @@ -18,8 +18,6 @@ #ifndef RED_CHANNEL_CLIENT_H_ #define RED_CHANNEL_CLIENT_H_ -#include <glib-object.h> -#include <gio/gio.h> #include <common/marshaller.h> #include "red-pipe-item.h" @@ -28,12 +26,28 @@ G_BEGIN_DECLS -#define RED_TYPE_CHANNEL_CLIENT red_channel_client_get_type() +struct RedChannelClientPrivate; -SPICE_DECLARE_TYPE(RedChannelClient, red_channel_client, CHANNEL_CLIENT); - -struct RedChannelClient: public GObject +class RedChannelClient { +public: + SPICE_CXX_GLIB_ALLOCATOR + + // This is made protected to avoid allocation on stack conflicting with + // reference counting +protected: + virtual ~RedChannelClient(); + +public: + RedChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps, + bool monitor_latency=false); + virtual bool init(); + + RedChannelClientPrivate *priv = nullptr; + bool is_connected() const; static void default_migrate(RedChannelClient *rcc); bool is_waiting_for_migrate_data() const; @@ -137,22 +151,19 @@ struct RedChannelClient: public GObject void block_read(); void unblock_read(); - void ref() { g_object_ref(this); } - void unref() { g_object_unref(this); } - - RedChannelClientPrivate *priv; -}; - -struct RedChannelClientClass -{ - GObjectClass parent_class; + void ref() { g_atomic_int_inc(&_ref); } + void unref() { if (g_atomic_int_dec_and_test(&_ref)) delete this; } /* configure socket connected to the client */ - bool (*config_socket)(RedChannelClient *rcc); - uint8_t *(*alloc_recv_buf)(RedChannelClient *channel, uint16_t type, uint32_t size); - void (*release_recv_buf)(RedChannelClient *channel, uint16_t type, uint32_t size, uint8_t *msg); + virtual bool config_socket() { return true; } + virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size)=0; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg)=0; + + virtual void on_disconnect() {}; - void (*on_disconnect)(RedChannelClient *rcc); + /* Private data */ +private: + gint _ref = 1; }; #define SPICE_SERVER_ERROR spice_server_error_quark() diff --git a/server/red-common.h b/server/red-common.h index 378be9f4..68e9be0a 100644 --- a/server/red-common.h +++ b/server/red-common.h @@ -128,6 +128,20 @@ typedef struct GListIter { { return G_TYPE_INSTANCE_GET_CLASS(obj, \ module_obj_name ## _get_type(), ModuleObjName ## Class); } +/* This macro allows to use GLib for a class hieranrchy allocation. + * The aims are: + * - do not depend on C++ runtime, just C; + * - do not throw memory exception from a C library; + * - zero out the structure like GOject did, we are not still + * initializing automatically all members; + * - do not allow to allocate array of this type, do not mix fine + * with reference counting and inheritance. + */ +#define SPICE_CXX_GLIB_ALLOCATOR \ + void *operator new(size_t size) { return g_malloc0(size); } \ + void operator delete(void *p) { g_free(p); } \ + void* operator new[](size_t count); + #ifdef __cplusplus #include <glib-object.h> @@ -137,6 +151,12 @@ inline GParamFlags operator|(GParamFlags a, GParamFlags b) } #endif +// XXX todo remove, just for easy portability +#define XXX_CAST(from, to, name) \ +static inline to* name(from *p) { \ + return p ? static_cast<to*>(p) : nullptr; \ +} + SPICE_END_DECLS #endif /* RED_COMMON_H_ */ diff --git a/server/smartcard-channel-client.cpp b/server/smartcard-channel-client.cpp index ac825ab9..6cfbeacb 100644 --- a/server/smartcard-channel-client.cpp +++ b/server/smartcard-channel-client.cpp @@ -20,140 +20,111 @@ #include "smartcard-channel-client.h" +XXX_CAST(RedChannelClient, SmartCardChannelClient, SMARTCARD_CHANNEL_CLIENT) + struct SmartCardChannelClientPrivate { - RedCharDeviceSmartcard *smartcard; + SPICE_CXX_GLIB_ALLOCATOR + + RedCharDeviceSmartcard *smartcard = nullptr; /* 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 */ + RedCharDeviceWriteBuffer *write_buf = nullptr; + /* was the client msg received into a RedCharDeviceWriteBuffer + * or was it explicitly malloced */ + bool msg_in_write_buf = false; }; -G_DEFINE_TYPE_WITH_PRIVATE(SmartCardChannelClient, smart_card_channel_client, - RED_TYPE_CHANNEL_CLIENT) - typedef struct RedErrorItem { RedPipeItem base; VSCMsgHeader vheader; VSCMsgError error; } RedErrorItem; -static uint8_t * -smartcard_channel_client_alloc_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size); -static void -smartcard_channel_client_release_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, - uint32_t size, uint8_t *msg); -static void smartcard_channel_client_on_disconnect(RedChannelClient *rcc); - -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) +SmartCardChannelClient::SmartCardChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps): + RedChannelClient(channel, client, stream, caps), + priv(new SmartCardChannelClientPrivate()) { - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - client_class->alloc_recv_buf = smartcard_channel_client_alloc_msg_rcv_buf; - client_class->release_recv_buf = smartcard_channel_client_release_msg_rcv_buf; - client_class->on_disconnect = smartcard_channel_client_on_disconnect; - - object_class->finalize = smart_card_channel_client_finalize; } -static void -smart_card_channel_client_init(SmartCardChannelClient *self) +SmartCardChannelClient::~SmartCardChannelClient() { - self->priv = (SmartCardChannelClientPrivate*) - smart_card_channel_client_get_instance_private(self); + if (priv->smartcard) { + g_object_remove_weak_pointer(G_OBJECT(priv->smartcard), + (gpointer*)&priv->smartcard); + } + delete priv; } SmartCardChannelClient* smartcard_channel_client_create(RedChannel *channel, RedClient *client, RedStream *stream, RedChannelCapabilities *caps) { - SmartCardChannelClient *rcc; - - rcc = (SmartCardChannelClient *) - g_initable_new(TYPE_SMARTCARD_CHANNEL_CLIENT, - NULL, NULL, - "channel", channel, - "client", client, - "stream", stream, - "caps", caps, - NULL); - + auto rcc = new SmartCardChannelClient(channel, client, stream, caps); + if (!rcc->init()) { + rcc->unref(); + rcc = nullptr; + } return rcc; } -static uint8_t * -smartcard_channel_client_alloc_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size) +uint8_t * +SmartCardChannelClient::alloc_recv_buf(uint16_t type, uint32_t size) { - SmartCardChannelClient *scc = SMARTCARD_CHANNEL_CLIENT(rcc); - /* TODO: only one reader is actually supported. When we fix the code to support * multiple readers, we will probably associate different devices to * different channels */ - if (!scc->priv->smartcard) { - scc->priv->msg_in_write_buf = FALSE; - return (uint8_t*) g_malloc(size); + if (!priv->smartcard) { + priv->msg_in_write_buf = FALSE; + return (uint8_t *) g_malloc(size); } else { RedCharDeviceSmartcard *smartcard; spice_assert(smartcard_get_n_readers() == 1); - smartcard = scc->priv->smartcard; - spice_assert(smartcard_char_device_get_client(smartcard) || scc->priv->smartcard); - spice_assert(!scc->priv->write_buf); - scc->priv->write_buf = - red_char_device_write_buffer_get_client(RED_CHAR_DEVICE(smartcard), rcc, size); + smartcard = priv->smartcard; + spice_assert(smartcard_char_device_get_client(smartcard) || priv->smartcard); + spice_assert(!priv->write_buf); + priv->write_buf = + red_char_device_write_buffer_get_client(RED_CHAR_DEVICE(smartcard), this, size); - if (!scc->priv->write_buf) { + if (!priv->write_buf) { spice_error("failed to allocate write buffer"); return NULL; } - scc->priv->msg_in_write_buf = TRUE; - return scc->priv->write_buf->buf; + priv->msg_in_write_buf = TRUE; + return priv->write_buf->buf; } } -static void -smartcard_channel_client_release_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size, uint8_t *msg) +void +SmartCardChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) { - SmartCardChannelClient *scc = SMARTCARD_CHANNEL_CLIENT(rcc); - /* todo: only one reader is actually supported. When we fix the code to support * multiple readers, we will porbably associate different devices to * differenc channels */ - if (!scc->priv->msg_in_write_buf) { - spice_assert(!scc->priv->write_buf); + if (!priv->msg_in_write_buf) { + spice_assert(!priv->write_buf); g_free(msg); } else { - if (scc->priv->write_buf) { /* msg hasn't been pushed to the guest */ - spice_assert(scc->priv->write_buf->buf == msg); - red_char_device_write_buffer_release(RED_CHAR_DEVICE(scc->priv->smartcard), - &scc->priv->write_buf); + if (priv->write_buf) { /* msg hasn't been pushed to the guest */ + spice_assert(priv->write_buf->buf == msg); + red_char_device_write_buffer_release(RED_CHAR_DEVICE(priv->smartcard), + &priv->write_buf); } } } -static void smartcard_channel_client_on_disconnect(RedChannelClient *rcc) +void SmartCardChannelClient::on_disconnect() { - SmartCardChannelClient *scc = SMARTCARD_CHANNEL_CLIENT(rcc); - RedCharDeviceSmartcard *device = scc->priv->smartcard; + RedCharDeviceSmartcard *device = priv->smartcard; if (device) { - smartcard_char_device_detach_client(device, scc); + smartcard_char_device_detach_client(device, this); smartcard_char_device_notify_reader_remove(device); } } diff --git a/server/smartcard-channel-client.h b/server/smartcard-channel-client.h index c0b340db..b7e8de26 100644 --- a/server/smartcard-channel-client.h +++ b/server/smartcard-channel-client.h @@ -18,39 +18,29 @@ #ifndef SMARTCARD_CHANNEL_CLIENT_H_ #define SMARTCARD_CHANNEL_CLIENT_H_ -#include <glib-object.h> - #include "smartcard.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)) - struct SmartCardChannelClientPrivate; -struct SmartCardChannelClient final: public RedChannelClient +class SmartCardChannelClient final: public RedChannelClient { - SmartCardChannelClientPrivate *priv; +protected: + ~SmartCardChannelClient(); +public: + SmartCardChannelClientPrivate *const priv = nullptr; + SmartCardChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps); + +private: + virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size) override; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) override; + virtual void on_disconnect() override; }; -struct SmartCardChannelClientClass -{ - RedChannelClientClass parent_class; -}; - -GType smart_card_channel_client_get_type(void) G_GNUC_CONST; - SmartCardChannelClient* smartcard_channel_client_create(RedChannel *channel, RedClient *client, RedStream *stream, RedChannelCapabilities *caps); diff --git a/server/smartcard.cpp b/server/smartcard.cpp index 3e0fa6ae..4f3b77cb 100644 --- a/server/smartcard.cpp +++ b/server/smartcard.cpp @@ -30,6 +30,8 @@ #include "smartcard-channel-client.h" #include "migration-protocol.h" +XXX_CAST(RedChannelClient, SmartCardChannelClient, SMARTCARD_CHANNEL_CLIENT) + /* * TODO: the code doesn't really support multiple readers. * For example: smartcard_char_device_add_to_readers calls smartcard_init, diff --git a/server/sound.cpp b/server/sound.cpp index 51deb0da..ee7aef55 100644 --- a/server/sound.cpp +++ b/server/sound.cpp @@ -79,19 +79,17 @@ typedef struct SpiceRecordState RecordChannel; typedef void (*snd_channel_on_message_done_proc)(SndChannelClient *client); -#define TYPE_SND_CHANNEL_CLIENT snd_channel_client_get_type() -#define SND_CHANNEL_CLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_SND_CHANNEL_CLIENT, SndChannelClient)) -GType snd_channel_client_get_type(void) G_GNUC_CONST; - struct PersistentPipeItem: public RedPipeItem { SndChannelClient *client; }; /* Connects an audio client to a Spice client */ -struct SndChannelClient: public RedChannelClient +class SndChannelClient: public RedChannelClient { +public: + using RedChannelClient::RedChannelClient; + bool active; bool client_active; @@ -103,19 +101,13 @@ struct SndChannelClient: public RedChannelClient PersistentPipeItem persistent_pipe_item; snd_channel_on_message_done_proc on_message_done; -}; - -typedef struct SndChannelClientClass { - RedChannelClientClass parent_class; -} SndChannelClientClass; - -static void playback_channel_client_initable_interface_init(GInitableIface *iface); -static void record_channel_client_initable_interface_init(GInitableIface *iface); -static GInitableIface *playback_channel_client_parent_initable_iface; -static GInitableIface *record_channel_client_parent_initable_iface; -G_DEFINE_TYPE(SndChannelClient, snd_channel_client, RED_TYPE_CHANNEL_CLIENT) + virtual bool config_socket() override; + virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size) override; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) override; +}; +static void snd_playback_alloc_frames(PlaybackChannelClient *playback); enum { RED_PIPE_ITEM_PERSISTENT = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, @@ -138,31 +130,27 @@ struct AudioFrameContainer AudioFrame items[NUM_AUDIO_FRAMES]; }; -#define TYPE_PLAYBACK_CHANNEL_CLIENT playback_channel_client_get_type() -#define PLAYBACK_CHANNEL_CLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_PLAYBACK_CHANNEL_CLIENT, PlaybackChannelClient)) -GType playback_channel_client_get_type(void) G_GNUC_CONST; - -struct PlaybackChannelClient final: public SndChannelClient -{ - AudioFrameContainer *frames; - AudioFrame *free_frames; - AudioFrame *in_progress; /* Frame being sent to the client */ - AudioFrame *pending_frame; /* Next frame to send to the client */ - uint32_t mode; - uint32_t latency; - SndCodec codec; +class PlaybackChannelClient final: public SndChannelClient +{ +protected: + ~PlaybackChannelClient(); +public: + PlaybackChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps); + virtual bool init() override; + + AudioFrameContainer *frames = nullptr; + AudioFrame *free_frames = nullptr; + AudioFrame *in_progress = nullptr; /* Frame being sent to the client */ + AudioFrame *pending_frame = nullptr; /* Next frame to send to the client */ + uint32_t mode = SPICE_AUDIO_DATA_MODE_RAW; + uint32_t latency = 0; + SndCodec codec = nullptr; uint8_t encode_buf[SND_CODEC_MAX_COMPRESSED_BYTES]; }; -typedef struct PlaybackChannelClientClass { - SndChannelClientClass parent_class; -} PlaybackChannelClientClass; - -G_DEFINE_TYPE_WITH_CODE(PlaybackChannelClient, playback_channel_client, TYPE_SND_CHANNEL_CLIENT, - G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, - playback_channel_client_initable_interface_init)) - typedef struct SpiceVolumeState { uint16_t *volume; uint8_t volume_nchannels; @@ -219,31 +207,24 @@ typedef struct RecordChannelClass { G_DEFINE_TYPE(RecordChannel, record_channel, TYPE_SND_CHANNEL) -#define TYPE_RECORD_CHANNEL_CLIENT record_channel_client_get_type() -#define RECORD_CHANNEL_CLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_RECORD_CHANNEL_CLIENT, RecordChannelClient)) -GType record_channel_client_get_type(void) G_GNUC_CONST; - -struct RecordChannelClient final: public SndChannelClient +class RecordChannelClient final: public SndChannelClient { +protected: + ~RecordChannelClient(); +public: + using SndChannelClient::SndChannelClient; + virtual bool init() override; + uint32_t samples[RECORD_SAMPLES_SIZE]; - uint32_t write_pos; - uint32_t read_pos; - uint32_t mode; - uint32_t mode_time; - uint32_t start_time; - SndCodec codec; + uint32_t write_pos = 0; + uint32_t read_pos = 0; + uint32_t mode = SPICE_AUDIO_DATA_MODE_RAW; + uint32_t mode_time = 0; + uint32_t start_time = 0; + SndCodec codec = nullptr; uint8_t decode_buf[SND_CODEC_MAX_FRAME_BYTES]; }; -typedef struct RecordChannelClientClass { - SndChannelClientClass parent_class; -} RecordChannelClientClass; - -G_DEFINE_TYPE_WITH_CODE(RecordChannelClient, record_channel_client, TYPE_SND_CHANNEL_CLIENT, - G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, - record_channel_client_initable_interface_init)) - /* A list of all Spice{Playback,Record}State objects */ static GList *snd_channels; @@ -350,6 +331,8 @@ const char* spice_audio_data_mode_to_string(gint mode) return "unknown audio codec"; } +XXX_CAST(RedChannelClient, RecordChannelClient, RECORD_CHANNEL_CLIENT) + static bool record_channel_handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, void *message) { @@ -415,7 +398,7 @@ static bool snd_channel_send_migrate(SndChannelClient *client) static bool snd_playback_send_migrate(PlaybackChannelClient *client) { - return snd_channel_send_migrate(SND_CHANNEL_CLIENT(client)); + return snd_channel_send_migrate(client); } static bool snd_send_volume(SndChannelClient *client, uint32_t cap, int msg) @@ -446,7 +429,7 @@ static bool snd_send_volume(SndChannelClient *client, uint32_t cap, int msg) static bool snd_playback_send_volume(PlaybackChannelClient *playback_client) { - return snd_send_volume(SND_CHANNEL_CLIENT(playback_client), SPICE_PLAYBACK_CAP_VOLUME, + return snd_send_volume(playback_client, SPICE_PLAYBACK_CAP_VOLUME, SPICE_MSG_PLAYBACK_VOLUME); } @@ -472,7 +455,7 @@ static bool snd_send_mute(SndChannelClient *client, uint32_t cap, int msg) static bool snd_playback_send_mute(PlaybackChannelClient *playback_client) { - return snd_send_mute(SND_CHANNEL_CLIENT(playback_client), SPICE_PLAYBACK_CAP_VOLUME, + return snd_send_mute(playback_client, SPICE_PLAYBACK_CAP_VOLUME, SPICE_MSG_PLAYBACK_MUTE); } @@ -521,7 +504,7 @@ static bool snd_playback_send_stop(PlaybackChannelClient *playback_client) static int snd_playback_send_ctl(PlaybackChannelClient *playback_client) { - SndChannelClient *client = SND_CHANNEL_CLIENT(playback_client); + SndChannelClient *client = playback_client; if ((client->client_active = client->active)) { return snd_playback_send_start(playback_client); @@ -560,7 +543,7 @@ static bool snd_record_send_stop(RecordChannelClient *record_client) static int snd_record_send_ctl(RecordChannelClient *record_client) { - SndChannelClient *client = SND_CHANNEL_CLIENT(record_client); + SndChannelClient *client = record_client; if ((client->client_active = client->active)) { return snd_record_send_start(record_client); @@ -571,13 +554,13 @@ static int snd_record_send_ctl(RecordChannelClient *record_client) static bool snd_record_send_volume(RecordChannelClient *record_client) { - return snd_send_volume(SND_CHANNEL_CLIENT(record_client), SPICE_RECORD_CAP_VOLUME, + return snd_send_volume(record_client, SPICE_RECORD_CAP_VOLUME, SPICE_MSG_RECORD_VOLUME); } static bool snd_record_send_mute(RecordChannelClient *record_client) { - return snd_send_mute(SND_CHANNEL_CLIENT(record_client), SPICE_RECORD_CAP_VOLUME, + return snd_send_mute(record_client, SPICE_RECORD_CAP_VOLUME, SPICE_MSG_RECORD_MUTE); } @@ -587,7 +570,7 @@ static bool snd_record_send_migrate(RecordChannelClient *record_client) * the client receives RECORD_STOP from the src before the migration completion * notification (when the vm is stopped). * Afterwards, when the vm starts on the dest, the client receives RECORD_START. */ - return snd_channel_send_migrate(SND_CHANNEL_CLIENT(record_client)); + return snd_channel_send_migrate(record_client); } static bool snd_playback_send_write(PlaybackChannelClient *playback_client) @@ -596,7 +579,7 @@ static bool snd_playback_send_write(PlaybackChannelClient *playback_client) SpiceMarshaller *m = rcc->get_marshaller(); AudioFrame *frame; SpiceMsgPlaybackPacket msg; - RedPipeItem *pipe_item = &SND_CHANNEL_CLIENT(playback_client)->persistent_pipe_item; + RedPipeItem *pipe_item = &playback_client->persistent_pipe_item; rcc->init_send_data(SPICE_MSG_PLAYBACK_DATA); @@ -666,25 +649,22 @@ static void snd_persistent_pipe_item_free(struct RedPipeItem *item) static void snd_send(SndChannelClient * client) { - RedChannelClient *rcc; - - g_return_if_fail(RED_IS_CHANNEL_CLIENT(client)); - - rcc = client; - if (!rcc->pipe_is_empty() || !client->command) { + if (!client->pipe_is_empty()|| !client->command) { return; } // just append a dummy item and push! red_pipe_item_init_full(&client->persistent_pipe_item, RED_PIPE_ITEM_PERSISTENT, snd_persistent_pipe_item_free); client->persistent_pipe_item.client = client; - rcc->pipe_add_push(&client->persistent_pipe_item); + client->pipe_add_push(&client->persistent_pipe_item); } +XXX_CAST(RedChannelClient, PlaybackChannelClient, PLAYBACK_CHANNEL_CLIENT) + static void playback_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedPipeItem *item) { PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(rcc); - SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); + SndChannelClient *client = playback_client; client->command &= SND_PLAYBACK_MODE_MASK|SND_PLAYBACK_PCM_MASK| SND_CTRL_MASK|SND_VOLUME_MUTE_MASK| @@ -744,7 +724,7 @@ static void playback_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedP static void record_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedPipeItem *item) { RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(rcc); - SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); + SndChannelClient *client = record_client; client->command &= SND_CTRL_MASK|SND_VOLUME_MUTE_MASK|SND_MIGRATE_MASK; while (client->command) { @@ -776,10 +756,10 @@ static void record_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedPip snd_send(client); } -static bool snd_channel_client_config_socket(RedChannelClient *rcc) +bool SndChannelClient::config_socket() { - RedStream *stream = rcc->get_stream(); - RedClient *red_client = rcc->get_client(); + RedStream *stream = get_stream(); + RedClient *red_client = get_client(); MainChannelClient *mcc = red_client_get_main(red_client); #ifdef SO_PRIORITY @@ -787,7 +767,7 @@ static bool snd_channel_client_config_socket(RedChannelClient *rcc) if (setsockopt(stream->socket, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) == -1) { if (errno != ENOTSUP) { - red_channel_warning(rcc->get_channel(), + red_channel_warning(get_channel(), "setsockopt failed, %s", strerror(errno)); } } @@ -797,7 +777,7 @@ static bool snd_channel_client_config_socket(RedChannelClient *rcc) int tos = IPTOS_LOWDELAY; if (setsockopt(stream->socket, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) == -1) { if (errno != ENOTSUP) { - red_channel_warning(rcc->get_channel(), + red_channel_warning(get_channel(), "setsockopt failed, %s", strerror(errno)); } @@ -809,23 +789,20 @@ static bool snd_channel_client_config_socket(RedChannelClient *rcc) return true; } -static uint8_t* -snd_channel_client_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) +uint8_t* +SndChannelClient::alloc_recv_buf(uint16_t type, uint32_t size) { - SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); // If message is too big allocate one, this should never happen - if (size > sizeof(client->receive_buf)) { + if (size > sizeof(receive_buf)) { return (uint8_t*) g_malloc(size); } - return client->receive_buf; + return receive_buf; } -static void -snd_channel_client_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size, - uint8_t *msg) +void +SndChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) { - SndChannelClient *client = SND_CHANNEL_CLIENT(rcc); - if (msg != client->receive_buf) { + if (msg != receive_buf) { g_free(msg); } } @@ -976,20 +953,20 @@ SPICE_GNUC_VISIBLE void spice_server_playback_put_samples(SpicePlaybackInstance } } playback_client = frame->client; - if (!playback_client || snd_channel_get_client(sin->st) != SND_CHANNEL_CLIENT(playback_client)) { + if (!playback_client || snd_channel_get_client(sin->st) != playback_client) { /* lost last reference, client has been destroyed previously */ spice_debug("audio samples belong to a disconnected client"); return; } - spice_assert(SND_CHANNEL_CLIENT(playback_client)->active); + spice_assert(playback_client->active); if (playback_client->pending_frame) { snd_playback_free_frame(playback_client, playback_client->pending_frame); } frame->time = reds_get_mm_time(); playback_client->pending_frame = frame; - snd_set_command(SND_CHANNEL_CLIENT(playback_client), SND_PLAYBACK_PCM_MASK); - snd_send(SND_CHANNEL_CLIENT(playback_client)); + snd_set_command(playback_client, SND_PLAYBACK_PCM_MASK); + snd_send(playback_client); } void snd_set_playback_latency(RedClient *client, uint32_t latency) @@ -1029,74 +1006,65 @@ static int snd_desired_audio_mode(bool playback_compression, int frequency, return SPICE_AUDIO_DATA_MODE_RAW; } -static void -playback_channel_client_finalize(GObject *object) +PlaybackChannelClient::~PlaybackChannelClient() { int i; - PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(object); - SndChannelClient *client = SND_CHANNEL_CLIENT(playback_client); // free frames, unref them for (i = 0; i < NUM_AUDIO_FRAMES; ++i) { - playback_client->frames->items[i].client = NULL; + frames->items[i].client = NULL; } - if (--playback_client->frames->refs == 0) { - g_free(playback_client->frames); + if (--frames->refs == 0) { + g_free(frames); } - if (client->active) { - reds_enable_mm_time(snd_channel_get_server(client)); + if (active) { + reds_enable_mm_time(snd_channel_get_server(this)); } - snd_codec_destroy(&playback_client->codec); - - G_OBJECT_CLASS(playback_channel_client_parent_class)->finalize(object); + snd_codec_destroy(&codec); } -static void -playback_channel_client_constructed(GObject *object) + +PlaybackChannelClient::PlaybackChannelClient(RedChannel *channel, + RedClient *client, + RedStream *stream, + RedChannelCapabilities *caps): + SndChannelClient(channel, client, stream, caps) { - PlaybackChannelClient *playback_client = PLAYBACK_CHANNEL_CLIENT(object); - RedChannelClient *rcc = playback_client; - RedChannel *red_channel = rcc->get_channel(); - SndChannel *channel = SND_CHANNEL(red_channel); - SndChannelClient *scc = SND_CHANNEL_CLIENT(playback_client); + snd_playback_alloc_frames(this); - G_OBJECT_CLASS(playback_channel_client_parent_class)->constructed(object); + RedChannel *red_channel = get_channel(); + SndChannel *snd_channel = SND_CHANNEL(red_channel); - scc->on_message_done = snd_playback_on_message_done; + on_message_done = snd_playback_on_message_done; - bool client_can_opus = rcc->test_remote_cap(SPICE_PLAYBACK_CAP_OPUS); + bool client_can_opus = test_remote_cap(SPICE_PLAYBACK_CAP_OPUS); bool playback_compression = reds_config_get_playback_compression(red_channel->get_server()); - int desired_mode = snd_desired_audio_mode(playback_compression, channel->frequency, client_can_opus); + int desired_mode = snd_desired_audio_mode(playback_compression, snd_channel->frequency, client_can_opus); if (desired_mode != SPICE_AUDIO_DATA_MODE_RAW) { - if (snd_codec_create(&playback_client->codec, desired_mode, channel->frequency, + if (snd_codec_create(&codec, desired_mode, snd_channel->frequency, SND_CODEC_ENCODE) == SND_CODEC_OK) { - playback_client->mode = desired_mode; + mode = desired_mode; } else { red_channel_warning(red_channel, "create encoder failed"); } } - spice_debug("playback client %p using mode %s", playback_client, - spice_audio_data_mode_to_string(playback_client->mode)); + spice_debug("playback client %p using mode %s", this, + spice_audio_data_mode_to_string(mode)); } -static gboolean playback_channel_client_initable_init(GInitable *initable, - GCancellable *cancellable, - GError **error) +bool PlaybackChannelClient::init() { - RedChannelClient *rcc = PLAYBACK_CHANNEL_CLIENT(initable); - gboolean success; - RedClient *red_client = rcc->get_client(); - SndChannelClient *scc = SND_CHANNEL_CLIENT(initable); - RedChannel *red_channel = rcc->get_channel(); + RedClient *red_client = get_client(); + SndChannelClient *scc = this; + RedChannel *red_channel = get_channel(); SndChannel *channel = SND_CHANNEL(red_channel); - success = playback_channel_client_parent_initable_iface->init(initable, cancellable, error); - if (!success) { - return FALSE; + if (!SndChannelClient::init()) { + return false; } if (!red_client_during_migrate_at_target(red_client)) { @@ -1111,19 +1079,10 @@ static gboolean playback_channel_client_initable_init(GInitable *initable, } snd_send(scc); - return TRUE; -} - -static void playback_channel_client_initable_interface_init(GInitableIface *iface) -{ - playback_channel_client_parent_initable_iface = - (GInitableIface *) g_type_interface_peek_parent(iface); - - iface->init = playback_channel_client_initable_init; + return true; } -static void snd_set_peer(RedChannel *red_channel, RedClient *client, RedStream *stream, - RedChannelCapabilities *caps, GType type) +static void snd_set_peer_common(RedChannel *red_channel) { SndChannel *channel = SND_CHANNEL(red_channel); SndChannelClient *snd_client = snd_channel_get_client(channel); @@ -1132,26 +1091,22 @@ static void snd_set_peer(RedChannel *red_channel, RedClient *client, RedStream * if (snd_client) { snd_client->disconnect(); } - - snd_client = (SndChannelClient *) - g_initable_new(type, - NULL, NULL, - "channel", channel, - "client", client, - "stream", stream, - "caps", caps, - NULL); - g_warn_if_fail(snd_client != NULL); } static void snd_set_playback_peer(RedChannel *red_channel, RedClient *client, RedStream *stream, G_GNUC_UNUSED int migration, RedChannelCapabilities *caps) { - snd_set_peer(red_channel, client, stream, caps, - TYPE_PLAYBACK_CHANNEL_CLIENT); + snd_set_peer_common(red_channel); + + auto peer = new PlaybackChannelClient(red_channel, client, stream, caps); + if (!peer->init()) { + peer->unref(); + } } +XXX_CAST(RedChannelClient, SndChannelClient, SND_CHANNEL_CLIENT) + static void snd_migrate_channel_client(RedChannelClient *rcc) { snd_set_command(SND_CHANNEL_CLIENT(rcc), SND_MIGRATE_MASK); @@ -1263,57 +1218,42 @@ SPICE_GNUC_VISIBLE void spice_server_set_record_rate(SpiceRecordInstance *sin, u snd_set_rate(sin->st, frequency, SPICE_RECORD_CAP_OPUS); } -static void -record_channel_client_finalize(GObject *object) +RecordChannelClient::~RecordChannelClient() { - RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(object); - - snd_codec_destroy(&record_client->codec); - - G_OBJECT_CLASS(record_channel_client_parent_class)->finalize(object); + snd_codec_destroy(&codec); } -static gboolean record_channel_client_initable_init(GInitable *initable, - GCancellable *cancellable, - GError **error) +bool RecordChannelClient::init() { - gboolean success; - RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(initable); - RedChannel *red_channel = record_client->get_channel(); + RedChannel *red_channel = get_channel(); SndChannel *channel = SND_CHANNEL(red_channel); - SndChannelClient *scc = SND_CHANNEL_CLIENT(record_client); - success = record_channel_client_parent_initable_iface->init(initable, cancellable, error); - if (!success) { + if (!SndChannelClient::init()) { return FALSE; } if (channel->volume.volume_nchannels) { - snd_set_command(scc, SND_VOLUME_MUTE_MASK); + snd_set_command(this, SND_VOLUME_MUTE_MASK); } if (channel->active) { - record_channel_client_start(scc); + record_channel_client_start(this); } - snd_send(scc); + snd_send(this); return TRUE; } -static void record_channel_client_initable_interface_init(GInitableIface *iface) -{ - record_channel_client_parent_initable_iface = - (GInitableIface *) g_type_interface_peek_parent(iface); - - iface->init = record_channel_client_initable_init; -} - static void snd_set_record_peer(RedChannel *red_channel, RedClient *client, RedStream *stream, G_GNUC_UNUSED int migration, RedChannelCapabilities *caps) { - snd_set_peer(red_channel, client, stream, caps, - TYPE_RECORD_CHANNEL_CLIENT); + snd_set_peer_common(red_channel); + + auto peer = new RecordChannelClient(red_channel, client, stream, caps); + if (!peer->init()) { + peer->unref(); + } } static void add_channel(SndChannel *channel) @@ -1488,29 +1428,6 @@ void snd_set_playback_compression(bool on) } } -static void -snd_channel_client_class_init(SndChannelClientClass *klass) -{ - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - - client_class->config_socket = snd_channel_client_config_socket; - client_class->alloc_recv_buf = snd_channel_client_alloc_recv_buf; - client_class->release_recv_buf = snd_channel_client_release_recv_buf; -} - -static void -snd_channel_client_init(SndChannelClient *self) -{ -} - -static void -playback_channel_client_class_init(PlaybackChannelClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - object_class->constructed = playback_channel_client_constructed; - object_class->finalize = playback_channel_client_finalize; -} - static void snd_playback_alloc_frames(PlaybackChannelClient *playback) { int i; @@ -1522,23 +1439,3 @@ static void snd_playback_alloc_frames(PlaybackChannelClient *playback) snd_playback_free_frame(playback, &playback->frames->items[i]); } } - -static void -playback_channel_client_init(PlaybackChannelClient *playback) -{ - playback->mode = SPICE_AUDIO_DATA_MODE_RAW; - snd_playback_alloc_frames(playback); -} - -static void -record_channel_client_class_init(RecordChannelClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - object_class->finalize = record_channel_client_finalize; -} - -static void -record_channel_client_init(RecordChannelClient *record) -{ - record->mode = SPICE_AUDIO_DATA_MODE_RAW; -} diff --git a/server/spicevmc.cpp b/server/spicevmc.cpp index 20afd28a..a0d339d3 100644 --- a/server/spicevmc.cpp +++ b/server/spicevmc.cpp @@ -51,9 +51,6 @@ SPICE_DECLARE_TYPE(RedVmcChannel, red_vmc_channel, VMC_CHANNEL); SPICE_DECLARE_TYPE(RedVmcChannelPort, red_vmc_channel_port, VMC_CHANNEL_PORT); #define RED_TYPE_VMC_CHANNEL_PORT red_vmc_channel_port_get_type() -SPICE_DECLARE_TYPE(VmcChannelClient, vmc_channel_client, VMC_CHANNEL_CLIENT); -#define TYPE_VMC_CHANNEL_CLIENT vmc_channel_client_get_type() - SPICE_DECLARE_TYPE(RedVmcChannelUsbredir, red_vmc_channel_usbredir, VMC_CHANNEL_USBREDIR); #define RED_TYPE_VMC_CHANNEL_USBREDIR red_vmc_channel_usbredir_get_type() @@ -156,16 +153,15 @@ static void red_vmc_channel_port_init(RedVmcChannelPort *self) G_DEFINE_TYPE(RedVmcChannelPort, red_vmc_channel_port, RED_TYPE_VMC_CHANNEL) -struct VmcChannelClient final: public RedChannelClient +class VmcChannelClient final: public RedChannelClient { -}; + using RedChannelClient::RedChannelClient; -struct VmcChannelClientClass { - RedChannelClientClass parent_class; + virtual uint8_t *alloc_recv_buf(uint16_t type, uint32_t size) override; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) override; + virtual void on_disconnect() override; }; -G_DEFINE_TYPE(VmcChannelClient, vmc_channel_client, RED_TYPE_CHANNEL_CLIENT) - static RedChannelClient * vmc_channel_client_create(RedChannel *channel, RedClient *client, RedStream *stream, @@ -271,10 +267,6 @@ enum { RED_PIPE_ITEM_TYPE_PORT_EVENT, }; -static void spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, - uint32_t size, - uint8_t *msg); /* n is the data size (uncompressed) * msg_item -- the current pipe item with the uncompressed data * This function returns: @@ -411,13 +403,13 @@ static void spicevmc_char_dev_remove_client(RedCharDevice *self, channel->rcc->shutdown(); } -static void spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc) +void VmcChannelClient::on_disconnect() { RedVmcChannel *channel; SpiceCharDeviceInterface *sif; - RedClient *client = rcc->get_client(); + RedClient *client = get_client(); - channel = RED_VMC_CHANNEL(rcc->get_channel()); + channel = RED_VMC_CHANNEL(get_channel()); /* partial message which wasn't pushed to device */ red_char_device_write_buffer_release(channel->chardev, &channel->recv_from_client_buf); @@ -514,7 +506,7 @@ static bool spicevmc_red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size, void *msg) { - /* NOTE: *msg free by g_free() (when cb to spicevmc_red_channel_release_msg_rcv_buf + /* NOTE: *msg free by g_free() (when cb to VmcChannelClient::release_recv_buf * with the compressed msg type) */ RedVmcChannel *channel; SpiceCharDeviceInterface *sif; @@ -557,21 +549,19 @@ static void spicevmc_on_free_self_token(RedCharDevice *self) channel->rcc->unblock_read(); } -static uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, - uint32_t size) +uint8_t *VmcChannelClient::alloc_recv_buf(uint16_t type, uint32_t size) { switch (type) { case SPICE_MSGC_SPICEVMC_DATA: { - RedVmcChannel *channel = RED_VMC_CHANNEL(rcc->get_channel()); + RedVmcChannel *channel = RED_VMC_CHANNEL(get_channel()); assert(!channel->recv_from_client_buf); channel->recv_from_client_buf = red_char_device_write_buffer_get_server(channel->chardev, size, true); if (!channel->recv_from_client_buf) { - rcc->block_read(); + block_read(); return NULL; } return channel->recv_from_client_buf->buf; @@ -583,15 +573,12 @@ static uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, } -static void spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, - uint32_t size, - uint8_t *msg) +void VmcChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) { switch (type) { case SPICE_MSGC_SPICEVMC_DATA: { - RedVmcChannel *channel = RED_VMC_CHANNEL(rcc->get_channel()); + RedVmcChannel *channel = RED_VMC_CHANNEL(get_channel()); /* buffer wasn't pushed to device */ red_char_device_write_buffer_release(channel->chardev, &channel->recv_from_client_buf); break; @@ -929,36 +916,15 @@ red_char_device_spicevmc_new(SpiceCharDeviceInstance *sin, NULL); } -static void -vmc_channel_client_init(VmcChannelClient *self) -{ -} - -static void -vmc_channel_client_class_init(VmcChannelClientClass *klass) -{ - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - - client_class->alloc_recv_buf = spicevmc_red_channel_alloc_msg_rcv_buf; - client_class->release_recv_buf = spicevmc_red_channel_release_msg_rcv_buf; - client_class->on_disconnect = spicevmc_red_channel_client_on_disconnect; -} - static RedChannelClient * vmc_channel_client_create(RedChannel *channel, RedClient *client, RedStream *stream, RedChannelCapabilities *caps) { - RedChannelClient *rcc; - - rcc = (RedChannelClient *) - g_initable_new(TYPE_VMC_CHANNEL_CLIENT, - NULL, NULL, - "channel", channel, - "client", client, - "stream", stream, - "caps", caps, - NULL); - + auto rcc = new VmcChannelClient(channel, client, stream, caps); + if (!rcc->init()) { + delete rcc; + rcc = nullptr; + } return rcc; } diff --git a/server/stream-channel.cpp b/server/stream-channel.cpp index 46f73089..d578d356 100644 --- a/server/stream-channel.cpp +++ b/server/stream-channel.cpp @@ -28,42 +28,26 @@ #include "display-limits.h" #include "video-stream.h" // TODO remove, put common stuff -#define TYPE_STREAM_CHANNEL_CLIENT stream_channel_client_get_type() - -#define STREAM_CHANNEL_CLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_STREAM_CHANNEL_CLIENT, StreamChannelClient)) -#define STREAM_CHANNEL_CLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_STREAM_CHANNEL_CLIENT, StreamChannelClientClass)) -#define IS_STREAM_CHANNEL_CLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_STREAM_CHANNEL_CLIENT)) -#define IS_STREAM_CHANNEL_CLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_STREAM_CHANNEL_CLIENT)) -#define STREAM_CHANNEL_CLIENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_STREAM_CHANNEL_CLIENT, StreamChannelClientClass)) - -typedef struct StreamChannelClient StreamChannelClient; -typedef struct StreamChannelClientClass StreamChannelClientClass; - /* we need to inherit from CommonGraphicsChannelClient * to get buffer handling */ -struct StreamChannelClient final: public CommonGraphicsChannelClient +class StreamChannelClient final: public CommonGraphicsChannelClient { +protected: + ~StreamChannelClient(); +public: + using CommonGraphicsChannelClient::CommonGraphicsChannelClient; + + bool handle_preferred_video_codec_type(SpiceMsgcDisplayPreferredVideoCodecType *msg); + /* current video stream id, <0 if not initialized or * we are not sending a stream */ - int stream_id; + int stream_id = -1; /* Array with SPICE_VIDEO_CODEC_TYPE_ENUM_END elements, with the client * preference order (index) as value */ GArray *client_preferred_video_codecs; + virtual void on_disconnect() override; }; -struct StreamChannelClientClass { - CommonGraphicsChannelClientClass parent_class; -}; - -GType stream_channel_client_get_type(void) G_GNUC_CONST; - -G_DEFINE_TYPE(StreamChannelClient, stream_channel_client, TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT) - struct StreamChannel final: public RedChannel { /* current video stream id, <0 if not initialized or @@ -114,37 +98,11 @@ typedef struct StreamDataItem { #define PRIMARY_SURFACE_ID 0 -static void stream_channel_client_on_disconnect(RedChannelClient *rcc); -static bool -stream_channel_handle_preferred_video_codec_type(RedChannelClient *rcc, - SpiceMsgcDisplayPreferredVideoCodecType *msg); - RECORDER(stream_channel_data, 32, "Stream channel data packet"); -static void -stream_channel_client_finalize(GObject *object) +StreamChannelClient::~StreamChannelClient() { - StreamChannelClient *self = STREAM_CHANNEL_CLIENT(object); - g_clear_pointer(&self->client_preferred_video_codecs, g_array_unref); - - G_OBJECT_CLASS(stream_channel_client_parent_class)->finalize(object); -} - -static void -stream_channel_client_class_init(StreamChannelClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - RedChannelClientClass *channel_class = RED_CHANNEL_CLIENT_CLASS(klass); - - channel_class->on_disconnect = stream_channel_client_on_disconnect; - object_class->finalize = stream_channel_client_finalize; -} - -static void -stream_channel_client_init(StreamChannelClient *client) -{ - client->stream_id = -1; + g_clear_pointer(&client_preferred_video_codecs, g_array_unref); } static void @@ -155,10 +113,10 @@ request_new_stream(StreamChannel *channel, StreamMsgStartStop *start) } } -static void -stream_channel_client_on_disconnect(RedChannelClient *rcc) +void +StreamChannelClient::on_disconnect() { - StreamChannel *channel = STREAM_CHANNEL(rcc->get_channel()); + StreamChannel *channel = STREAM_CHANNEL(get_channel()); // if there are still some client connected keep streaming // TODO, maybe would be worth sending new codecs if they are better @@ -179,17 +137,11 @@ static StreamChannelClient* stream_channel_client_new(StreamChannel *channel, RedClient *client, RedStream *stream, int mig_target, RedChannelCapabilities *caps) { - StreamChannelClient *rcc; - - rcc = (StreamChannelClient *) - g_initable_new(TYPE_STREAM_CHANNEL_CLIENT, - NULL, NULL, - "channel", channel, - "client", client, - "stream", stream, - "caps", caps, - NULL); - + auto rcc = new StreamChannelClient(RED_CHANNEL(channel), client, stream, caps); + if (!rcc->init()) { + rcc->unref(); + rcc = nullptr; + } return rcc; } @@ -227,6 +179,8 @@ marshall_monitors_config(RedChannelClient *rcc, StreamChannel *channel, SpiceMar spice_marshall_msg_display_monitors_config(m, &msg.config); } +XXX_CAST(RedChannelClient, StreamChannelClient, STREAM_CHANNEL_CLIENT) + static void stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item) { @@ -329,6 +283,8 @@ stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item) static bool handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, void *msg) { + StreamChannelClient *client = STREAM_CHANNEL_CLIENT(rcc); + switch (type) { case SPICE_MSGC_DISPLAY_INIT: case SPICE_MSGC_DISPLAY_PREFERRED_COMPRESSION: @@ -340,7 +296,7 @@ handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, void *msg) /* client should not send this message */ return false; case SPICE_MSGC_DISPLAY_PREFERRED_VIDEO_CODEC_TYPE: - return stream_channel_handle_preferred_video_codec_type(rcc, + return client->handle_preferred_video_codec_type( (SpiceMsgcDisplayPreferredVideoCodecType *)msg); default: return RedChannelClient::handle_message(rcc, type, size, msg); @@ -407,18 +363,15 @@ stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs) return num; } -static bool -stream_channel_handle_preferred_video_codec_type(RedChannelClient *rcc, - SpiceMsgcDisplayPreferredVideoCodecType *msg) +bool +StreamChannelClient::handle_preferred_video_codec_type(SpiceMsgcDisplayPreferredVideoCodecType *msg) { - StreamChannelClient *client = STREAM_CHANNEL_CLIENT(rcc); - if (msg->num_of_codecs == 0) { return true; } - g_clear_pointer(&client->client_preferred_video_codecs, g_array_unref); - client->client_preferred_video_codecs = video_stream_parse_preferred_codecs(msg); + g_clear_pointer(&client_preferred_video_codecs, g_array_unref); + client_preferred_video_codecs = video_stream_parse_preferred_codecs(msg); return true; } diff --git a/server/tests/test-channel.cpp b/server/tests/test-channel.cpp index ed083f1a..9c294f2a 100644 --- a/server/tests/test-channel.cpp +++ b/server/tests/test-channel.cpp @@ -47,31 +47,19 @@ struct RedTestChannelClass G_DEFINE_TYPE(RedTestChannel, red_test_channel, RED_TYPE_CHANNEL) -SPICE_DECLARE_TYPE(RedTestChannelClient, red_test_channel_client, TEST_CHANNEL_CLIENT); -#define RED_TYPE_TEST_CHANNEL_CLIENT red_test_channel_client_get_type() - -struct RedTestChannelClient final: public RedChannelClient -{ -}; - -struct RedTestChannelClientClass +class RedTestChannelClient final: public RedChannelClient { - RedChannelClientClass parent_class; + using RedChannelClient::RedChannelClient; + virtual uint8_t * alloc_recv_buf(uint16_t type, uint32_t size) override; + virtual void release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) override; }; -G_DEFINE_TYPE(RedTestChannelClient, red_test_channel_client, RED_TYPE_CHANNEL_CLIENT) - static void red_test_channel_init(RedTestChannel *self) { } static void -red_test_channel_client_init(RedTestChannelClient *self) -{ -} - -static void test_channel_send_item(RedChannelClient *rcc, RedPipeItem *item) { } @@ -81,15 +69,9 @@ test_connect_client(RedChannel *channel, RedClient *client, RedStream *stream, int migration, RedChannelCapabilities *caps) { RedChannelClient *rcc; - rcc = (RedChannelClient *) - g_initable_new(RED_TYPE_TEST_CHANNEL_CLIENT, - NULL, NULL, - "channel", channel, - "client", client, - "stream", stream, - "caps", caps, - NULL); + rcc = new RedTestChannelClient(channel, client, stream, caps); g_assert_nonnull(rcc); + g_assert_true(rcc->init()); // requires an ACK after 10 messages rcc->ack_set_client_window(10); @@ -115,27 +97,18 @@ red_test_channel_class_init(RedTestChannelClass *klass) channel_class->connect = test_connect_client; } -static uint8_t * -red_test_channel_client_alloc_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size) +uint8_t * +RedTestChannelClient::alloc_recv_buf(uint16_t type, uint32_t size) { return (uint8_t*) g_malloc(size); } -static void -red_test_channel_client_release_msg_rcv_buf(RedChannelClient *rcc, - uint16_t type, uint32_t size, uint8_t *msg) +void +RedTestChannelClient::release_recv_buf(uint16_t type, uint32_t size, uint8_t *msg) { g_free(msg); } -static void -red_test_channel_client_class_init(RedTestChannelClientClass *klass) -{ - RedChannelClientClass *client_class = RED_CHANNEL_CLIENT_CLASS(klass); - client_class->alloc_recv_buf = red_test_channel_client_alloc_msg_rcv_buf; - client_class->release_recv_buf = red_test_channel_client_release_msg_rcv_buf; -} - /* * Main test part |