mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-08 21:14:11 +00:00
Convert RedChannel hierarchy to GObject
Acked-by: Frediano Ziglio <fziglio@redhat.com> Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
parent
8f43c8348c
commit
96e94c6f32
@ -102,6 +102,8 @@ libserver_la_SOURCES = \
|
|||||||
red-channel-client.c \
|
red-channel-client.c \
|
||||||
red-channel-client.h \
|
red-channel-client.h \
|
||||||
red-channel-client-private.h \
|
red-channel-client-private.h \
|
||||||
|
dummy-channel.c \
|
||||||
|
dummy-channel.h \
|
||||||
dummy-channel-client.c \
|
dummy-channel-client.c \
|
||||||
dummy-channel-client.h \
|
dummy-channel-client.h \
|
||||||
red-common.h \
|
red-common.h \
|
||||||
|
|||||||
@ -29,6 +29,11 @@
|
|||||||
|
|
||||||
#define CHANNEL_RECEIVE_BUF_SIZE 1024
|
#define CHANNEL_RECEIVE_BUF_SIZE 1024
|
||||||
|
|
||||||
|
G_DEFINE_ABSTRACT_TYPE(CommonGraphicsChannel, common_graphics_channel, RED_TYPE_CHANNEL)
|
||||||
|
|
||||||
|
#define GRAPHICS_CHANNEL_PRIVATE(o) \
|
||||||
|
(G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannelPrivate))
|
||||||
|
|
||||||
struct CommonGraphicsChannelPrivate
|
struct CommonGraphicsChannelPrivate
|
||||||
{
|
{
|
||||||
QXLInstance *qxl;
|
QXLInstance *qxl;
|
||||||
@ -43,7 +48,7 @@ struct CommonGraphicsChannelPrivate
|
|||||||
static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size)
|
static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
CommonGraphicsChannel *common = SPICE_CONTAINEROF(channel, CommonGraphicsChannel, base);
|
CommonGraphicsChannel *common = COMMON_GRAPHICS_CHANNEL(channel);
|
||||||
|
|
||||||
/* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is dynamic */
|
/* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is dynamic */
|
||||||
if (type == SPICE_MSGC_MIGRATE_DATA) {
|
if (type == SPICE_MSGC_MIGRATE_DATA) {
|
||||||
@ -65,6 +70,48 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP0,
|
||||||
|
PROP_QXL
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_graphics_channel_get_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CommonGraphicsChannel *self = COMMON_GRAPHICS_CHANNEL(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_QXL:
|
||||||
|
g_value_set_pointer(value, self->priv->qxl);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_graphics_channel_set_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CommonGraphicsChannel *self = COMMON_GRAPHICS_CHANNEL(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_QXL:
|
||||||
|
self->priv->qxl = g_value_get_pointer(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int common_channel_config_socket(RedChannelClient *rcc)
|
int common_channel_config_socket(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
RedClient *client = red_channel_client_get_client(rcc);
|
RedClient *client = red_channel_client_get_client(rcc);
|
||||||
@ -106,40 +153,36 @@ int common_channel_config_socket(RedChannelClient *rcc)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommonGraphicsChannel* common_graphics_channel_new(RedsState *server,
|
|
||||||
QXLInstance *qxl,
|
static void
|
||||||
const SpiceCoreInterfaceInternal *core,
|
common_graphics_channel_class_init(CommonGraphicsChannelClass *klass)
|
||||||
int size, uint32_t channel_type,
|
|
||||||
int migration_flags,
|
|
||||||
ChannelCbs *channel_cbs,
|
|
||||||
channel_handle_parsed_proc handle_parsed)
|
|
||||||
{
|
{
|
||||||
RedChannel *channel = NULL;
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
CommonGraphicsChannel *common;
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
spice_return_val_if_fail(channel_cbs, NULL);
|
g_type_class_add_private(klass, sizeof(CommonGraphicsChannelPrivate));
|
||||||
spice_return_val_if_fail(!channel_cbs->alloc_recv_buf, NULL);
|
|
||||||
spice_return_val_if_fail(!channel_cbs->release_recv_buf, NULL);
|
|
||||||
|
|
||||||
if (!channel_cbs->config_socket)
|
object_class->get_property = common_graphics_channel_get_property;
|
||||||
channel_cbs->config_socket = common_channel_config_socket;
|
object_class->set_property = common_graphics_channel_set_property;
|
||||||
channel_cbs->alloc_recv_buf = common_alloc_recv_buf;
|
|
||||||
channel_cbs->release_recv_buf = common_release_recv_buf;
|
|
||||||
|
|
||||||
channel = red_channel_create_parser(size, server,
|
channel_class->config_socket = common_channel_config_socket;
|
||||||
core, channel_type,
|
channel_class->alloc_recv_buf = common_alloc_recv_buf;
|
||||||
qxl->id, TRUE /* handle_acks */,
|
channel_class->release_recv_buf = common_release_recv_buf;
|
||||||
spice_get_client_channel_parser(channel_type, NULL),
|
|
||||||
handle_parsed,
|
|
||||||
channel_cbs,
|
|
||||||
migration_flags);
|
|
||||||
spice_return_val_if_fail(channel, NULL);
|
|
||||||
|
|
||||||
common = COMMON_GRAPHICS_CHANNEL(channel);
|
g_object_class_install_property(object_class,
|
||||||
/* FIXME remove leak */
|
PROP_QXL,
|
||||||
common->priv = g_new0(CommonGraphicsChannelPrivate, 1);
|
g_param_spec_pointer("qxl",
|
||||||
common->priv->qxl = qxl;
|
"qxl",
|
||||||
return common;
|
"QXLInstance for this channel",
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_graphics_channel_init(CommonGraphicsChannel *self)
|
||||||
|
{
|
||||||
|
self->priv = GRAPHICS_CHANNEL_PRIVATE(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel *self, gboolean value)
|
void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel *self, gboolean value)
|
||||||
|
|||||||
@ -18,21 +18,47 @@
|
|||||||
#ifndef _COMMON_GRAPHICS_CHANNEL_H
|
#ifndef _COMMON_GRAPHICS_CHANNEL_H
|
||||||
#define _COMMON_GRAPHICS_CHANNEL_H
|
#define _COMMON_GRAPHICS_CHANNEL_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
#include "red-channel.h"
|
#include "red-channel.h"
|
||||||
#include "red-channel-client.h"
|
#include "red-channel-client.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
int common_channel_config_socket(RedChannelClient *rcc);
|
int common_channel_config_socket(RedChannelClient *rcc);
|
||||||
|
|
||||||
#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30)
|
#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30)
|
||||||
|
|
||||||
|
#define TYPE_COMMON_GRAPHICS_CHANNEL common_graphics_channel_get_type()
|
||||||
|
|
||||||
|
#define COMMON_GRAPHICS_CHANNEL(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannel))
|
||||||
|
#define COMMON_GRAPHICS_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannelClass))
|
||||||
|
#define COMMON_IS_GRAPHICS_CHANNEL(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_COMMON_GRAPHICS_CHANNEL))
|
||||||
|
#define COMMON_IS_GRAPHICS_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COMMON_GRAPHICS_CHANNEL))
|
||||||
|
#define COMMON_GRAPHICS_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COMMON_GRAPHICS_CHANNEL, CommonGraphicsChannelClass))
|
||||||
|
|
||||||
|
typedef struct CommonGraphicsChannel CommonGraphicsChannel;
|
||||||
|
typedef struct CommonGraphicsChannelClass CommonGraphicsChannelClass;
|
||||||
typedef struct CommonGraphicsChannelPrivate CommonGraphicsChannelPrivate;
|
typedef struct CommonGraphicsChannelPrivate CommonGraphicsChannelPrivate;
|
||||||
typedef struct CommonGraphicsChannel {
|
|
||||||
RedChannel base; // Must be the first thing
|
struct CommonGraphicsChannel
|
||||||
|
{
|
||||||
|
RedChannel parent;
|
||||||
|
|
||||||
CommonGraphicsChannelPrivate *priv;
|
CommonGraphicsChannelPrivate *priv;
|
||||||
} CommonGraphicsChannel;
|
};
|
||||||
|
|
||||||
#define COMMON_GRAPHICS_CHANNEL(Channel) ((CommonGraphicsChannel*)(Channel))
|
struct CommonGraphicsChannelClass
|
||||||
|
{
|
||||||
|
RedChannelClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType common_graphics_channel_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel *self, gboolean value);
|
void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel *self, gboolean value);
|
||||||
gboolean common_graphics_channel_get_during_target_migrate(CommonGraphicsChannel *self);
|
gboolean common_graphics_channel_get_during_target_migrate(CommonGraphicsChannel *self);
|
||||||
@ -76,12 +102,6 @@ static inline void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
|
|||||||
red_channel_apply_clients_data(channel, red_pipe_add_verb_proxy, GUINT_TO_POINTER(verb));
|
red_channel_apply_clients_data(channel, red_pipe_add_verb_proxy, GUINT_TO_POINTER(verb));
|
||||||
}
|
}
|
||||||
|
|
||||||
CommonGraphicsChannel* common_graphics_channel_new(RedsState *server,
|
G_END_DECLS
|
||||||
QXLInstance *qxl,
|
|
||||||
const SpiceCoreInterfaceInternal *core,
|
|
||||||
int size, uint32_t channel_type,
|
|
||||||
int migration_flags,
|
|
||||||
ChannelCbs *channel_cbs,
|
|
||||||
channel_handle_parsed_proc handle_parsed);
|
|
||||||
|
|
||||||
#endif /* _COMMON_GRAPHICS_CHANNEL_H */
|
#endif /* _COMMON_GRAPHICS_CHANNEL_H */
|
||||||
|
|||||||
@ -28,8 +28,6 @@
|
|||||||
#include "reds.h"
|
#include "reds.h"
|
||||||
#include "red-qxl.h"
|
#include "red-qxl.h"
|
||||||
|
|
||||||
#define CURSOR_CHANNEL(channel) ((CursorChannel*)(channel))
|
|
||||||
|
|
||||||
typedef struct CursorItem {
|
typedef struct CursorItem {
|
||||||
QXLInstance *qxl;
|
QXLInstance *qxl;
|
||||||
int refs;
|
int refs;
|
||||||
@ -38,13 +36,10 @@ typedef struct CursorItem {
|
|||||||
|
|
||||||
G_STATIC_ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
|
G_STATIC_ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
|
||||||
|
|
||||||
typedef struct RedCursorPipeItem {
|
struct CursorChannel
|
||||||
RedPipeItem base;
|
{
|
||||||
CursorItem *cursor_item;
|
CommonGraphicsChannel parent;
|
||||||
} RedCursorPipeItem;
|
|
||||||
|
|
||||||
typedef struct CursorChannelPrivate CursorChannelPrivate;
|
|
||||||
struct CursorChannelPrivate {
|
|
||||||
CursorItem *item;
|
CursorItem *item;
|
||||||
int cursor_visible;
|
int cursor_visible;
|
||||||
SpicePoint16 cursor_position;
|
SpicePoint16 cursor_position;
|
||||||
@ -53,12 +48,18 @@ struct CursorChannelPrivate {
|
|||||||
uint32_t mouse_mode;
|
uint32_t mouse_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CursorChannel {
|
struct CursorChannelClass
|
||||||
CommonGraphicsChannel common; // Must be the first thing
|
{
|
||||||
|
CommonGraphicsChannelClass parent_class;
|
||||||
CursorChannelPrivate priv[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct RedCursorPipeItem {
|
||||||
|
RedPipeItem base;
|
||||||
|
CursorItem *cursor_item;
|
||||||
|
} RedCursorPipeItem;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(CursorChannel, cursor_channel, TYPE_COMMON_GRAPHICS_CHANNEL)
|
||||||
|
|
||||||
static void cursor_pipe_item_free(RedPipeItem *pipe_item);
|
static void cursor_pipe_item_free(RedPipeItem *pipe_item);
|
||||||
|
|
||||||
static CursorItem *cursor_item_new(QXLInstance *qxl, RedCursorCmd *cmd)
|
static CursorItem *cursor_item_new(QXLInstance *qxl, RedCursorCmd *cmd)
|
||||||
@ -105,10 +106,10 @@ static void cursor_item_unref(CursorItem *item)
|
|||||||
|
|
||||||
static void cursor_set_item(CursorChannel *cursor, CursorItem *item)
|
static void cursor_set_item(CursorChannel *cursor, CursorItem *item)
|
||||||
{
|
{
|
||||||
if (cursor->priv->item)
|
if (cursor->item)
|
||||||
cursor_item_unref(cursor->priv->item);
|
cursor_item_unref(cursor->item);
|
||||||
|
|
||||||
cursor->priv->item = item ? cursor_item_ref(item) : NULL;
|
cursor->item = item ? cursor_item_ref(item) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RedPipeItem *new_cursor_pipe_item(RedChannelClient *rcc, void *data, int num)
|
static RedPipeItem *new_cursor_pipe_item(RedChannelClient *rcc, void *data, int num)
|
||||||
@ -197,12 +198,12 @@ static void red_marshall_cursor_init(CursorChannelClient *ccc, SpiceMarshaller *
|
|||||||
cursor_channel = CURSOR_CHANNEL(red_channel_client_get_channel(rcc));
|
cursor_channel = CURSOR_CHANNEL(red_channel_client_get_channel(rcc));
|
||||||
|
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, NULL);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, NULL);
|
||||||
msg.visible = cursor_channel->priv->cursor_visible;
|
msg.visible = cursor_channel->cursor_visible;
|
||||||
msg.position = cursor_channel->priv->cursor_position;
|
msg.position = cursor_channel->cursor_position;
|
||||||
msg.trail_length = cursor_channel->priv->cursor_trail_length;
|
msg.trail_length = cursor_channel->cursor_trail_length;
|
||||||
msg.trail_frequency = cursor_channel->priv->cursor_trail_frequency;
|
msg.trail_frequency = cursor_channel->cursor_trail_frequency;
|
||||||
|
|
||||||
cursor_fill(ccc, &msg.cursor, cursor_channel->priv->item, &info);
|
cursor_fill(ccc, &msg.cursor, cursor_channel->item, &info);
|
||||||
spice_marshall_msg_cursor_init(base_marshaller, &msg);
|
spice_marshall_msg_cursor_init(base_marshaller, &msg);
|
||||||
add_buf_from_info(base_marshaller, &info);
|
add_buf_from_info(base_marshaller, &info);
|
||||||
}
|
}
|
||||||
@ -212,8 +213,7 @@ static void cursor_marshall(CursorChannelClient *ccc,
|
|||||||
RedCursorPipeItem *cursor_pipe_item)
|
RedCursorPipeItem *cursor_pipe_item)
|
||||||
{
|
{
|
||||||
RedChannelClient *rcc = RED_CHANNEL_CLIENT(ccc);
|
RedChannelClient *rcc = RED_CHANNEL_CLIENT(ccc);
|
||||||
CursorChannel *cursor_channel = SPICE_CONTAINEROF(red_channel_client_get_channel(rcc),
|
CursorChannel *cursor_channel = CURSOR_CHANNEL(red_channel_client_get_channel(rcc));
|
||||||
CursorChannel, common.base);
|
|
||||||
CursorItem *item = cursor_pipe_item->cursor_item;
|
CursorItem *item = cursor_pipe_item->cursor_item;
|
||||||
RedPipeItem *pipe_item = &cursor_pipe_item->base;
|
RedPipeItem *pipe_item = &cursor_pipe_item->base;
|
||||||
RedCursorCmd *cmd;
|
RedCursorCmd *cmd;
|
||||||
@ -237,7 +237,7 @@ static void cursor_marshall(CursorChannelClient *ccc,
|
|||||||
|
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, pipe_item);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, pipe_item);
|
||||||
cursor_set.position = cmd->u.set.position;
|
cursor_set.position = cmd->u.set.position;
|
||||||
cursor_set.visible = cursor_channel->priv->cursor_visible;
|
cursor_set.visible = cursor_channel->cursor_visible;
|
||||||
|
|
||||||
cursor_fill(ccc, &cursor_set.cursor, item, &info);
|
cursor_fill(ccc, &cursor_set.cursor, item, &info);
|
||||||
spice_marshall_msg_cursor_set(m, &cursor_set);
|
spice_marshall_msg_cursor_set(m, &cursor_set);
|
||||||
@ -307,24 +307,14 @@ static void cursor_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_it
|
|||||||
CursorChannel* cursor_channel_new(RedsState *server, QXLInstance *qxl,
|
CursorChannel* cursor_channel_new(RedsState *server, QXLInstance *qxl,
|
||||||
const SpiceCoreInterfaceInternal *core)
|
const SpiceCoreInterfaceInternal *core)
|
||||||
{
|
{
|
||||||
CursorChannel *cursor_channel;
|
|
||||||
CommonGraphicsChannel *channel = NULL;
|
|
||||||
ChannelCbs cbs = {
|
|
||||||
.on_disconnect = cursor_channel_client_on_disconnect,
|
|
||||||
.send_item = cursor_channel_send_item,
|
|
||||||
};
|
|
||||||
|
|
||||||
spice_info("create cursor channel");
|
spice_info("create cursor channel");
|
||||||
channel = common_graphics_channel_new(server, qxl, core,
|
return g_object_new(TYPE_CURSOR_CHANNEL,
|
||||||
sizeof(CursorChannel),
|
"spice-server", server,
|
||||||
SPICE_CHANNEL_CURSOR, 0,
|
"core-interface", core,
|
||||||
&cbs, red_channel_client_handle_message);
|
"channel-type", SPICE_CHANNEL_CURSOR,
|
||||||
|
"migration-flags", 0,
|
||||||
cursor_channel = CURSOR_CHANNEL(channel);
|
"qxl", qxl,
|
||||||
cursor_channel->priv->cursor_visible = TRUE;
|
NULL);
|
||||||
cursor_channel->priv->mouse_mode = SPICE_MOUSE_MODE_SERVER;
|
|
||||||
|
|
||||||
return cursor_channel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd)
|
void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd)
|
||||||
@ -341,31 +331,31 @@ void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd)
|
|||||||
|
|
||||||
switch (cursor_cmd->type) {
|
switch (cursor_cmd->type) {
|
||||||
case QXL_CURSOR_SET:
|
case QXL_CURSOR_SET:
|
||||||
cursor->priv->cursor_visible = cursor_cmd->u.set.visible;
|
cursor->cursor_visible = cursor_cmd->u.set.visible;
|
||||||
cursor_set_item(cursor, cursor_item);
|
cursor_set_item(cursor, cursor_item);
|
||||||
break;
|
break;
|
||||||
case QXL_CURSOR_MOVE:
|
case QXL_CURSOR_MOVE:
|
||||||
cursor_show = !cursor->priv->cursor_visible;
|
cursor_show = !cursor->cursor_visible;
|
||||||
cursor->priv->cursor_visible = TRUE;
|
cursor->cursor_visible = TRUE;
|
||||||
cursor->priv->cursor_position = cursor_cmd->u.position;
|
cursor->cursor_position = cursor_cmd->u.position;
|
||||||
break;
|
break;
|
||||||
case QXL_CURSOR_HIDE:
|
case QXL_CURSOR_HIDE:
|
||||||
cursor->priv->cursor_visible = FALSE;
|
cursor->cursor_visible = FALSE;
|
||||||
break;
|
break;
|
||||||
case QXL_CURSOR_TRAIL:
|
case QXL_CURSOR_TRAIL:
|
||||||
cursor->priv->cursor_trail_length = cursor_cmd->u.trail.length;
|
cursor->cursor_trail_length = cursor_cmd->u.trail.length;
|
||||||
cursor->priv->cursor_trail_frequency = cursor_cmd->u.trail.frequency;
|
cursor->cursor_trail_frequency = cursor_cmd->u.trail.frequency;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spice_warning("invalid cursor command %u", cursor_cmd->type);
|
spice_warning("invalid cursor command %u", cursor_cmd->type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (red_channel_is_connected(&cursor->common.base) &&
|
if (red_channel_is_connected(RED_CHANNEL(cursor)) &&
|
||||||
(cursor->priv->mouse_mode == SPICE_MOUSE_MODE_SERVER
|
(cursor->mouse_mode == SPICE_MOUSE_MODE_SERVER
|
||||||
|| cursor_cmd->type != QXL_CURSOR_MOVE
|
|| cursor_cmd->type != QXL_CURSOR_MOVE
|
||||||
|| cursor_show)) {
|
|| cursor_show)) {
|
||||||
red_channel_pipes_new_add(&cursor->common.base,
|
red_channel_pipes_new_add(RED_CHANNEL(cursor),
|
||||||
new_cursor_pipe_item, cursor_item);
|
new_cursor_pipe_item, cursor_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,21 +364,21 @@ void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd)
|
|||||||
|
|
||||||
void cursor_channel_reset(CursorChannel *cursor)
|
void cursor_channel_reset(CursorChannel *cursor)
|
||||||
{
|
{
|
||||||
RedChannel *channel = &cursor->common.base;
|
RedChannel *channel = RED_CHANNEL(cursor);
|
||||||
|
|
||||||
spice_return_if_fail(cursor);
|
spice_return_if_fail(cursor);
|
||||||
|
|
||||||
cursor_set_item(cursor, NULL);
|
cursor_set_item(cursor, NULL);
|
||||||
cursor->priv->cursor_visible = TRUE;
|
cursor->cursor_visible = TRUE;
|
||||||
cursor->priv->cursor_position.x = cursor->priv->cursor_position.y = 0;
|
cursor->cursor_position.x = cursor->cursor_position.y = 0;
|
||||||
cursor->priv->cursor_trail_length = cursor->priv->cursor_trail_frequency = 0;
|
cursor->cursor_trail_length = cursor->cursor_trail_frequency = 0;
|
||||||
|
|
||||||
if (red_channel_is_connected(channel)) {
|
if (red_channel_is_connected(channel)) {
|
||||||
red_channel_pipes_add_type(channel, RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
|
red_channel_pipes_add_type(channel, RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
|
||||||
if (!common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor))) {
|
if (!common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor))) {
|
||||||
red_pipes_add_verb(channel, SPICE_MSG_CURSOR_RESET);
|
red_pipes_add_verb(channel, SPICE_MSG_CURSOR_RESET);
|
||||||
}
|
}
|
||||||
if (!red_channel_wait_all_sent(&cursor->common.base,
|
if (!red_channel_wait_all_sent(channel,
|
||||||
COMMON_CLIENT_TIMEOUT)) {
|
COMMON_CLIENT_TIMEOUT)) {
|
||||||
red_channel_apply_clients(channel,
|
red_channel_apply_clients(channel,
|
||||||
red_channel_client_disconnect_if_pending_send);
|
red_channel_client_disconnect_if_pending_send);
|
||||||
@ -400,7 +390,7 @@ static void cursor_channel_init_client(CursorChannel *cursor, CursorChannelClien
|
|||||||
{
|
{
|
||||||
spice_return_if_fail(cursor);
|
spice_return_if_fail(cursor);
|
||||||
|
|
||||||
if (!red_channel_is_connected(&cursor->common.base)
|
if (!red_channel_is_connected(RED_CHANNEL(cursor))
|
||||||
|| common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor))) {
|
|| common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor))) {
|
||||||
spice_debug("during_target_migrate: skip init");
|
spice_debug("during_target_migrate: skip init");
|
||||||
return;
|
return;
|
||||||
@ -413,7 +403,7 @@ static void cursor_channel_init_client(CursorChannel *cursor, CursorChannelClien
|
|||||||
red_channel_pipes_add_type(RED_CHANNEL(cursor), RED_PIPE_ITEM_TYPE_CURSOR_INIT);
|
red_channel_pipes_add_type(RED_CHANNEL(cursor), RED_PIPE_ITEM_TYPE_CURSOR_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_channel_init(CursorChannel *cursor)
|
void cursor_channel_do_init(CursorChannel *cursor)
|
||||||
{
|
{
|
||||||
cursor_channel_init_client(cursor, NULL);
|
cursor_channel_init_client(cursor, NULL);
|
||||||
}
|
}
|
||||||
@ -422,7 +412,7 @@ void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32_t mode)
|
|||||||
{
|
{
|
||||||
spice_return_if_fail(cursor);
|
spice_return_if_fail(cursor);
|
||||||
|
|
||||||
cursor->priv->mouse_mode = mode;
|
cursor->mouse_mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cursor_channel_connect(CursorChannel *cursor, RedClient *client, RedsStream *stream,
|
void cursor_channel_connect(CursorChannel *cursor, RedClient *client, RedsStream *stream,
|
||||||
@ -447,3 +437,22 @@ void cursor_channel_connect(CursorChannel *cursor, RedClient *client, RedsStream
|
|||||||
|
|
||||||
cursor_channel_init_client(cursor, ccc);
|
cursor_channel_init_client(cursor, ccc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursor_channel_class_init(CursorChannelClass *klass)
|
||||||
|
{
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_CURSOR, NULL);
|
||||||
|
channel_class->handle_parsed = red_channel_client_handle_message;
|
||||||
|
|
||||||
|
channel_class->on_disconnect = cursor_channel_client_on_disconnect;
|
||||||
|
channel_class->send_item = cursor_channel_send_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cursor_channel_init(CursorChannel *self)
|
||||||
|
{
|
||||||
|
self->cursor_visible = TRUE;
|
||||||
|
self->mouse_mode = SPICE_MOUSE_MODE_SERVER;
|
||||||
|
}
|
||||||
|
|||||||
@ -21,12 +21,27 @@
|
|||||||
#include "common-graphics-channel.h"
|
#include "common-graphics-channel.h"
|
||||||
#include "red-parse-qxl.h"
|
#include "red-parse-qxl.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This type it's a RedChannel class which implement cursor (mouse)
|
* This type it's a RedChannel class which implement cursor (mouse)
|
||||||
* movements.
|
* movements.
|
||||||
* A pointer to CursorChannel can be converted to a RedChannel.
|
* A pointer to CursorChannel can be converted to a RedChannel.
|
||||||
*/
|
*/
|
||||||
typedef struct CursorChannel CursorChannel;
|
typedef struct CursorChannel CursorChannel;
|
||||||
|
typedef struct CursorChannelClass CursorChannelClass;
|
||||||
|
|
||||||
|
#define TYPE_CURSOR_CHANNEL cursor_channel_get_type()
|
||||||
|
|
||||||
|
#define CURSOR_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_CURSOR_CHANNEL, CursorChannel))
|
||||||
|
#define CURSOR_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), TYPE_CURSOR_CHANNEL, CursorChannelClass))
|
||||||
|
#define IS_CURSOR_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_CURSOR_CHANNEL))
|
||||||
|
#define IS_CURSOR_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_CURSOR_CHANNEL))
|
||||||
|
#define CURSOR_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_CURSOR_CHANNEL, CursorChannelClass))
|
||||||
|
|
||||||
|
GType cursor_channel_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create CursorChannel.
|
* Create CursorChannel.
|
||||||
@ -48,7 +63,7 @@ CursorChannel* cursor_channel_new (RedsState *server, QXLInstance
|
|||||||
*/
|
*/
|
||||||
void cursor_channel_disconnect (CursorChannel *cursor);
|
void cursor_channel_disconnect (CursorChannel *cursor);
|
||||||
void cursor_channel_reset (CursorChannel *cursor);
|
void cursor_channel_reset (CursorChannel *cursor);
|
||||||
void cursor_channel_init (CursorChannel *cursor);
|
void cursor_channel_do_init (CursorChannel *cursor);
|
||||||
void cursor_channel_process_cmd (CursorChannel *cursor, RedCursorCmd *cursor_cmd);
|
void cursor_channel_process_cmd (CursorChannel *cursor, RedCursorCmd *cursor_cmd);
|
||||||
void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32_t mode);
|
void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32_t mode);
|
||||||
|
|
||||||
@ -70,4 +85,6 @@ void cursor_channel_connect (CursorChannel *cursor, RedClien
|
|||||||
*/
|
*/
|
||||||
void cursor_channel_client_migrate(RedChannelClient *client);
|
void cursor_channel_client_migrate(RedChannelClient *client);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* CURSOR_CHANNEL_H_ */
|
#endif /* CURSOR_CHANNEL_H_ */
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "dcc-private.h"
|
#include "dcc-private.h"
|
||||||
#include "display-channel.h"
|
#include "display-channel-private.h"
|
||||||
#include "red-channel-client-private.h"
|
#include "red-channel-client-private.h"
|
||||||
|
|
||||||
#include <common/marshaller.h>
|
#include <common/marshaller.h>
|
||||||
@ -185,8 +185,9 @@ static void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
|
|||||||
SpiceImage *image, SpiceImage *io_image,
|
SpiceImage *image, SpiceImage *io_image,
|
||||||
int is_lossy)
|
int is_lossy)
|
||||||
{
|
{
|
||||||
|
DisplayChannel *display_channel =
|
||||||
|
DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
|
||||||
DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
|
DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
|
||||||
DisplayChannel *display_channel = DCC_TO_DC(dcc);
|
|
||||||
|
|
||||||
if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
|
if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
|
||||||
spice_assert(image->descriptor.width * image->descriptor.height > 0);
|
spice_assert(image->descriptor.width * image->descriptor.height > 0);
|
||||||
@ -1817,7 +1818,7 @@ static void display_channel_marshall_migrate_data(RedChannelClient *rcc,
|
|||||||
ImageEncoders *encoders = dcc_get_encoders(dcc);
|
ImageEncoders *encoders = dcc_get_encoders(dcc);
|
||||||
SpiceMigrateDataDisplay display_data = {0,};
|
SpiceMigrateDataDisplay display_data = {0,};
|
||||||
|
|
||||||
display_channel = DCC_TO_DC(dcc);
|
display_channel = DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
|
||||||
|
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL);
|
||||||
spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_MAGIC);
|
spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_MAGIC);
|
||||||
@ -2120,8 +2121,8 @@ static void marshall_qxl_drawable(RedChannelClient *rcc,
|
|||||||
spice_return_if_fail(rcc);
|
spice_return_if_fail(rcc);
|
||||||
|
|
||||||
Drawable *item = dpi->drawable;
|
Drawable *item = dpi->drawable;
|
||||||
DisplayChannel *display = SPICE_CONTAINEROF(red_channel_client_get_channel(rcc),
|
DisplayChannel *display =
|
||||||
DisplayChannel, common.base);
|
DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
|
||||||
|
|
||||||
spice_return_if_fail(display);
|
spice_return_if_fail(display);
|
||||||
/* allow sized frames to be streamed, even if they where replaced by another frame, since
|
/* allow sized frames to be streamed, even if they where replaced by another frame, since
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "dcc-private.h"
|
#include "dcc-private.h"
|
||||||
#include "display-channel.h"
|
#include "display-channel.h"
|
||||||
|
#include "display-channel-private.h"
|
||||||
#include "red-channel-client-private.h"
|
#include "red-channel-client-private.h"
|
||||||
#include "main-channel-client.h"
|
#include "main-channel-client.h"
|
||||||
#include "spice-server-enums.h"
|
#include "spice-server-enums.h"
|
||||||
|
|||||||
@ -23,7 +23,6 @@
|
|||||||
#include "image-encoders.h"
|
#include "image-encoders.h"
|
||||||
#include "image-cache.h"
|
#include "image-cache.h"
|
||||||
#include "pixmap-cache.h"
|
#include "pixmap-cache.h"
|
||||||
#include "red-worker.h"
|
|
||||||
#include "display-limits.h"
|
#include "display-limits.h"
|
||||||
#include "red-channel-client.h"
|
#include "red-channel-client.h"
|
||||||
|
|
||||||
|
|||||||
76
server/display-channel-private.h
Normal file
76
server/display-channel-private.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2009-2015 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISPLAY_CHANNEL_PRIVATE_H_
|
||||||
|
#define DISPLAY_CHANNEL_PRIVATE_H_
|
||||||
|
|
||||||
|
#include "display-channel.h"
|
||||||
|
|
||||||
|
struct DisplayChannelPrivate
|
||||||
|
{
|
||||||
|
DisplayChannel *pub;
|
||||||
|
|
||||||
|
uint32_t bits_unique;
|
||||||
|
|
||||||
|
MonitorsConfig *monitors_config;
|
||||||
|
|
||||||
|
uint32_t renderer;
|
||||||
|
int enable_jpeg;
|
||||||
|
int enable_zlib_glz_wrap;
|
||||||
|
|
||||||
|
Ring current_list; // of TreeItem
|
||||||
|
uint32_t current_size;
|
||||||
|
|
||||||
|
uint32_t drawable_count;
|
||||||
|
_Drawable drawables[NUM_DRAWABLES];
|
||||||
|
_Drawable *free_drawables;
|
||||||
|
|
||||||
|
int stream_video;
|
||||||
|
GArray *video_codecs;
|
||||||
|
uint32_t stream_count;
|
||||||
|
Stream streams_buf[NUM_STREAMS];
|
||||||
|
Stream *free_streams;
|
||||||
|
Ring streams;
|
||||||
|
ItemTrace items_trace[NUM_TRACE_ITEMS];
|
||||||
|
uint32_t next_item_trace;
|
||||||
|
uint64_t streams_size_total;
|
||||||
|
|
||||||
|
RedSurface surfaces[NUM_SURFACES];
|
||||||
|
uint32_t n_surfaces;
|
||||||
|
SpiceImageSurfaces image_surfaces;
|
||||||
|
|
||||||
|
ImageCache image_cache;
|
||||||
|
|
||||||
|
int gl_draw_async_count;
|
||||||
|
|
||||||
|
/* TODO: some day unify this, make it more runtime.. */
|
||||||
|
stat_info_t add_stat;
|
||||||
|
stat_info_t exclude_stat;
|
||||||
|
stat_info_t __exclude_stat;
|
||||||
|
#ifdef RED_WORKER_STAT
|
||||||
|
uint32_t add_count;
|
||||||
|
uint32_t add_with_shadow_count;
|
||||||
|
#endif
|
||||||
|
#ifdef RED_STATISTICS
|
||||||
|
uint64_t *cache_hits_counter;
|
||||||
|
uint64_t *add_to_cache_counter;
|
||||||
|
uint64_t *non_cache_counter;
|
||||||
|
#endif
|
||||||
|
ImageEncoderSharedData encoder_shared_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DISPLAY_CHANNEL_PRIVATE_H_ */
|
||||||
@ -20,7 +20,69 @@
|
|||||||
|
|
||||||
#include <common/sw_canvas.h>
|
#include <common/sw_canvas.h>
|
||||||
|
|
||||||
#include "display-channel.h"
|
#include "display-channel-private.h"
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(DisplayChannel, display_channel, TYPE_COMMON_GRAPHICS_CHANNEL)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP0,
|
||||||
|
PROP_N_SURFACES,
|
||||||
|
PROP_VIDEO_CODECS
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
display_channel_get_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
DisplayChannel *self = DISPLAY_CHANNEL(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_N_SURFACES:
|
||||||
|
g_value_set_uint(value, self->priv->n_surfaces);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
display_channel_set_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
DisplayChannel *self = DISPLAY_CHANNEL(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_N_SURFACES:
|
||||||
|
self->priv->n_surfaces = g_value_get_uint(value);
|
||||||
|
self->priv->n_surfaces = MIN(self->priv->n_surfaces, NUM_SURFACES);
|
||||||
|
break;
|
||||||
|
case PROP_VIDEO_CODECS:
|
||||||
|
if (self->priv->video_codecs) {
|
||||||
|
g_array_unref(self->priv->video_codecs);
|
||||||
|
}
|
||||||
|
self->priv->video_codecs = g_array_ref(g_value_get_boxed(value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
display_channel_finalize(GObject *object)
|
||||||
|
{
|
||||||
|
DisplayChannel *self = DISPLAY_CHANNEL(object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(display_channel_parent_class)->finalize(object);
|
||||||
|
|
||||||
|
g_free(self->priv);
|
||||||
|
g_array_unref(self->priv->video_codecs);
|
||||||
|
}
|
||||||
|
|
||||||
static void drawable_draw(DisplayChannel *display, Drawable *drawable);
|
static void drawable_draw(DisplayChannel *display, Drawable *drawable);
|
||||||
static Drawable *display_channel_drawable_try_new(DisplayChannel *display,
|
static Drawable *display_channel_drawable_try_new(DisplayChannel *display,
|
||||||
@ -43,12 +105,16 @@ void display_channel_compress_stats_reset(DisplayChannel *display)
|
|||||||
image_encoder_shared_stat_reset(&display->priv->encoder_shared_data);
|
image_encoder_shared_stat_reset(&display->priv->encoder_shared_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_channel_compress_stats_print(const DisplayChannel *display_channel)
|
void display_channel_compress_stats_print(DisplayChannel *display_channel)
|
||||||
{
|
{
|
||||||
#ifdef COMPRESS_STAT
|
#ifdef COMPRESS_STAT
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
spice_return_if_fail(display_channel);
|
spice_return_if_fail(display_channel);
|
||||||
|
|
||||||
spice_info("==> Compression stats for display %u", display_channel->common.base.id);
|
g_object_get(display_channel, "id", &id, NULL);
|
||||||
|
|
||||||
|
spice_info("==> Compression stats for display %u", id);
|
||||||
image_encoder_shared_stat_print(&display_channel->priv->encoder_shared_data);
|
image_encoder_shared_stat_print(&display_channel->priv->encoder_shared_data);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -150,6 +216,11 @@ void display_channel_set_video_codecs(DisplayChannel *display, GArray *video_cod
|
|||||||
display->priv->video_codecs = g_array_ref(video_codecs);
|
display->priv->video_codecs = g_array_ref(video_codecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int display_channel_get_stream_video(DisplayChannel *display)
|
||||||
|
{
|
||||||
|
return display->priv->stream_video;
|
||||||
|
}
|
||||||
|
|
||||||
static void stop_streams(DisplayChannel *display)
|
static void stop_streams(DisplayChannel *display)
|
||||||
{
|
{
|
||||||
Ring *ring = &display->priv->streams;
|
Ring *ring = &display->priv->streams;
|
||||||
@ -280,7 +351,7 @@ static void pipes_add_drawable_after(DisplayChannel *display,
|
|||||||
pipes_add_drawable(display, drawable);
|
pipes_add_drawable(display, drawable);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (num_other_linked != g_list_length(display->common.base.clients)) {
|
if (num_other_linked != red_channel_get_n_clients(RED_CHANNEL(display))) {
|
||||||
GListIter iter;
|
GListIter iter;
|
||||||
spice_debug("TODO: not O(n^2)");
|
spice_debug("TODO: not O(n^2)");
|
||||||
FOREACH_DCC(display, iter, dcc) {
|
FOREACH_DCC(display, iter, dcc) {
|
||||||
@ -1115,18 +1186,18 @@ void display_channel_process_draw(DisplayChannel *display, RedDrawable *red_draw
|
|||||||
int display_channel_wait_for_migrate_data(DisplayChannel *display)
|
int display_channel_wait_for_migrate_data(DisplayChannel *display)
|
||||||
{
|
{
|
||||||
uint64_t end_time = spice_get_monotonic_time_ns() + DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT;
|
uint64_t end_time = spice_get_monotonic_time_ns() + DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT;
|
||||||
RedChannel *channel = &display->common.base;
|
|
||||||
RedChannelClient *rcc;
|
RedChannelClient *rcc;
|
||||||
int ret = FALSE;
|
int ret = FALSE;
|
||||||
|
GList *clients = red_channel_get_clients(RED_CHANNEL(display));
|
||||||
|
|
||||||
if (!red_channel_is_waiting_for_migrate_data(&display->common.base)) {
|
if (!red_channel_is_waiting_for_migrate_data(RED_CHANNEL(display))) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
spice_debug(NULL);
|
spice_debug(NULL);
|
||||||
spice_warn_if_fail(g_list_length(channel->clients) == 1);
|
spice_warn_if_fail(g_list_length(clients) == 1);
|
||||||
|
|
||||||
rcc = g_list_nth_data(channel->clients, 0);
|
rcc = g_list_nth_data(clients, 0);
|
||||||
|
|
||||||
g_object_ref(rcc);
|
g_object_ref(rcc);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -1831,8 +1902,7 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
|
|||||||
|
|
||||||
if (display->priv->renderer == RED_RENDERER_INVALID) {
|
if (display->priv->renderer == RED_RENDERER_INVALID) {
|
||||||
int i;
|
int i;
|
||||||
QXLInstance *qxl = common_graphics_channel_get_qxl(COMMON_GRAPHICS_CHANNEL(display));
|
RedsState *reds = red_channel_get_server(RED_CHANNEL(display));
|
||||||
RedsState *reds = red_qxl_get_server(qxl->st);
|
|
||||||
GArray *renderers = reds_get_renderers(reds);
|
GArray *renderers = reds_get_renderers(reds);
|
||||||
for (i = 0; i < renderers->len; i++) {
|
for (i = 0; i < renderers->len; i++) {
|
||||||
uint32_t renderer = g_array_index(renderers, uint32_t, i);
|
uint32_t renderer = g_array_index(renderers, uint32_t, i);
|
||||||
@ -1900,7 +1970,7 @@ static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t su
|
|||||||
|
|
||||||
spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), NULL);
|
spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), NULL);
|
||||||
|
|
||||||
return display->priv->surfaces[surface_id].context.canvas;
|
return p->surfaces[surface_id].context.canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayChannel* display_channel_new(RedsState *reds,
|
DisplayChannel* display_channel_new(RedsState *reds,
|
||||||
@ -1911,53 +1981,76 @@ DisplayChannel* display_channel_new(RedsState *reds,
|
|||||||
uint32_t n_surfaces)
|
uint32_t n_surfaces)
|
||||||
{
|
{
|
||||||
DisplayChannel *display;
|
DisplayChannel *display;
|
||||||
ChannelCbs cbs = {
|
|
||||||
.on_disconnect = on_disconnect,
|
/* FIXME: migrate is not used...? */
|
||||||
.send_item = dcc_send_item,
|
spice_info("create display channel");
|
||||||
.handle_migrate_flush_mark = handle_migrate_flush_mark,
|
display = g_object_new(TYPE_DISPLAY_CHANNEL,
|
||||||
.handle_migrate_data = handle_migrate_data,
|
"spice-server", reds,
|
||||||
.handle_migrate_data_get_serial = handle_migrate_data_get_serial,
|
"core-interface", core,
|
||||||
.config_socket = dcc_config_socket
|
"channel-type", SPICE_CHANNEL_DISPLAY,
|
||||||
};
|
"migration-flags",
|
||||||
|
(SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
|
||||||
|
"qxl", qxl,
|
||||||
|
"n-surfaces", n_surfaces,
|
||||||
|
"video-codecs", video_codecs,
|
||||||
|
NULL);
|
||||||
|
if (display) {
|
||||||
|
display_channel_set_stream_video(display, stream_video);
|
||||||
|
}
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id);
|
||||||
|
static void drawables_init(DisplayChannel *display);
|
||||||
|
static void
|
||||||
|
display_channel_init(DisplayChannel *self)
|
||||||
|
{
|
||||||
static SpiceImageSurfacesOps image_surfaces_ops = {
|
static SpiceImageSurfacesOps image_surfaces_ops = {
|
||||||
image_surfaces_get,
|
image_surfaces_get,
|
||||||
};
|
};
|
||||||
|
|
||||||
spice_info("create display channel");
|
/* must be manually allocated here since g_type_class_add_private() only
|
||||||
display = DISPLAY_CHANNEL(common_graphics_channel_new(
|
* supports structs smaller than 64k */
|
||||||
reds, qxl, core, sizeof(*display), SPICE_CHANNEL_DISPLAY,
|
self->priv = g_new0(DisplayChannelPrivate, 1);
|
||||||
SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
|
self->priv->pub = self;
|
||||||
&cbs, dcc_handle_message));
|
|
||||||
spice_return_val_if_fail(display, NULL);
|
|
||||||
display->priv->pub = display;
|
|
||||||
|
|
||||||
clockid_t stat_clock = CLOCK_THREAD_CPUTIME_ID;
|
image_encoder_shared_init(&self->priv->encoder_shared_data);
|
||||||
stat_init(&display->priv->add_stat, "add", stat_clock);
|
|
||||||
stat_init(&display->priv->exclude_stat, "exclude", stat_clock);
|
ring_init(&self->priv->current_list);
|
||||||
stat_init(&display->priv->__exclude_stat, "__exclude", stat_clock);
|
drawables_init(self);
|
||||||
|
self->priv->image_surfaces.ops = &image_surfaces_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
display_channel_constructed(GObject *object)
|
||||||
|
{
|
||||||
|
DisplayChannel *self = DISPLAY_CHANNEL(object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(display_channel_parent_class)->constructed(object);
|
||||||
|
|
||||||
|
spice_assert(self->priv->video_codecs);
|
||||||
|
|
||||||
|
self->priv->renderer = RED_RENDERER_INVALID;
|
||||||
|
|
||||||
|
stat_init(&self->priv->add_stat, "add", CLOCK_THREAD_CPUTIME_ID);
|
||||||
|
stat_init(&self->priv->exclude_stat, "exclude", CLOCK_THREAD_CPUTIME_ID);
|
||||||
|
stat_init(&self->priv->__exclude_stat, "__exclude", CLOCK_THREAD_CPUTIME_ID);
|
||||||
#ifdef RED_STATISTICS
|
#ifdef RED_STATISTICS
|
||||||
RedChannel *channel = RED_CHANNEL(display);
|
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
|
||||||
display->priv->cache_hits_counter = stat_add_counter(reds, channel->stat,
|
RedChannel *channel = RED_CHANNEL(self);
|
||||||
"cache_hits", TRUE);
|
self->priv->cache_hits_counter =
|
||||||
display->priv->add_to_cache_counter = stat_add_counter(reds, channel->stat,
|
stat_add_counter(reds, red_channel_get_stat_node(channel),
|
||||||
"add_to_cache", TRUE);
|
"cache_hits", TRUE);
|
||||||
display->priv->non_cache_counter = stat_add_counter(reds, channel->stat,
|
self->priv->add_to_cache_counter =
|
||||||
"non_cache", TRUE);
|
stat_add_counter(reds, red_channel_get_stat_node(channel),
|
||||||
|
"add_to_cache", TRUE);
|
||||||
|
self->priv->non_cache_counter =
|
||||||
|
stat_add_counter(reds, red_channel_get_stat_node(channel),
|
||||||
|
"non_cache", TRUE);
|
||||||
#endif
|
#endif
|
||||||
image_encoder_shared_init(&display->priv->encoder_shared_data);
|
image_cache_init(&self->priv->image_cache);
|
||||||
|
self->priv->stream_video = SPICE_STREAM_VIDEO_OFF;
|
||||||
display->priv->n_surfaces = MIN(n_surfaces, NUM_SURFACES);
|
display_channel_init_streams(self);
|
||||||
display->priv->renderer = RED_RENDERER_INVALID;
|
|
||||||
|
|
||||||
ring_init(&display->priv->current_list);
|
|
||||||
display->priv->image_surfaces.ops = &image_surfaces_ops;
|
|
||||||
drawables_init(display);
|
|
||||||
image_cache_init(&display->priv->image_cache);
|
|
||||||
display->priv->stream_video = stream_video;
|
|
||||||
display->priv->video_codecs = g_array_ref(video_codecs);
|
|
||||||
display_channel_init_streams(display);
|
|
||||||
|
|
||||||
return display;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_channel_process_surface_cmd(DisplayChannel *display,
|
void display_channel_process_surface_cmd(DisplayChannel *display,
|
||||||
@ -2113,6 +2206,48 @@ void display_channel_reset_image_cache(DisplayChannel *self)
|
|||||||
image_cache_reset(&self->priv->image_cache);
|
image_cache_reset(&self->priv->image_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
display_channel_class_init(DisplayChannelClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->get_property = display_channel_get_property;
|
||||||
|
object_class->set_property = display_channel_set_property;
|
||||||
|
object_class->constructed = display_channel_constructed;
|
||||||
|
object_class->finalize = display_channel_finalize;
|
||||||
|
|
||||||
|
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_DISPLAY, NULL);
|
||||||
|
channel_class->handle_parsed = dcc_handle_message;
|
||||||
|
|
||||||
|
channel_class->on_disconnect = on_disconnect;
|
||||||
|
channel_class->send_item = dcc_send_item;
|
||||||
|
channel_class->handle_migrate_flush_mark = handle_migrate_flush_mark;
|
||||||
|
channel_class->handle_migrate_data = handle_migrate_data;
|
||||||
|
channel_class->handle_migrate_data_get_serial = handle_migrate_data_get_serial;
|
||||||
|
channel_class->config_socket = dcc_config_socket;
|
||||||
|
|
||||||
|
g_object_class_install_property(object_class,
|
||||||
|
PROP_N_SURFACES,
|
||||||
|
g_param_spec_uint("n-surfaces",
|
||||||
|
"number of surfaces",
|
||||||
|
"Number of surfaces for this channel",
|
||||||
|
0, G_MAXUINT,
|
||||||
|
0,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_STATIC_STRINGS));
|
||||||
|
g_object_class_install_property(object_class,
|
||||||
|
PROP_VIDEO_CODECS,
|
||||||
|
g_param_spec_boxed("video-codecs",
|
||||||
|
"video codecs",
|
||||||
|
"Video Codecs",
|
||||||
|
G_TYPE_ARRAY,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_WRITABLE |
|
||||||
|
G_PARAM_STATIC_STRINGS));
|
||||||
|
}
|
||||||
|
|
||||||
void display_channel_debug_oom(DisplayChannel *display, const char *msg)
|
void display_channel_debug_oom(DisplayChannel *display, const char *msg)
|
||||||
{
|
{
|
||||||
RedChannel *channel = RED_CHANNEL(display);
|
RedChannel *channel = RED_CHANNEL(display);
|
||||||
|
|||||||
@ -37,7 +37,6 @@
|
|||||||
#include "migration-protocol.h"
|
#include "migration-protocol.h"
|
||||||
#include "main-dispatcher.h"
|
#include "main-dispatcher.h"
|
||||||
#include "spice-bitmap-utils.h"
|
#include "spice-bitmap-utils.h"
|
||||||
#include "image-cache.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
@ -45,7 +44,36 @@
|
|||||||
#include "image-encoders.h"
|
#include "image-encoders.h"
|
||||||
#include "common-graphics-channel.h"
|
#include "common-graphics-channel.h"
|
||||||
|
|
||||||
#define DISPLAY_CHANNEL(channel) ((DisplayChannel*)(channel))
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define TYPE_DISPLAY_CHANNEL display_channel_get_type()
|
||||||
|
|
||||||
|
#define DISPLAY_CHANNEL(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DISPLAY_CHANNEL, DisplayChannel))
|
||||||
|
#define DISPLAY_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DISPLAY_CHANNEL, DisplayChannelClass))
|
||||||
|
#define IS_DISPLAY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_DISPLAY_CHANNEL))
|
||||||
|
#define IS_DISPLAY_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DISPLAY_CHANNEL))
|
||||||
|
#define DISPLAY_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DISPLAY_CHANNEL, DisplayChannelClass))
|
||||||
|
|
||||||
|
typedef struct DisplayChannel DisplayChannel;
|
||||||
|
typedef struct DisplayChannelClass DisplayChannelClass;
|
||||||
|
typedef struct DisplayChannelPrivate DisplayChannelPrivate;
|
||||||
|
|
||||||
|
struct DisplayChannel
|
||||||
|
{
|
||||||
|
CommonGraphicsChannel parent;
|
||||||
|
|
||||||
|
DisplayChannelPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DisplayChannelClass
|
||||||
|
{
|
||||||
|
CommonGraphicsChannelClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType display_channel_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
typedef struct DependItem {
|
typedef struct DependItem {
|
||||||
Drawable *drawable;
|
Drawable *drawable;
|
||||||
@ -154,69 +182,8 @@ struct _Drawable {
|
|||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DisplayChannelPrivate DisplayChannelPrivate;
|
|
||||||
/* FIXME: move to separate file */
|
|
||||||
struct DisplayChannelPrivate
|
|
||||||
{
|
|
||||||
DisplayChannel *pub;
|
|
||||||
|
|
||||||
uint32_t bits_unique;
|
|
||||||
|
|
||||||
MonitorsConfig *monitors_config;
|
|
||||||
|
|
||||||
uint32_t renderer;
|
|
||||||
int enable_jpeg;
|
|
||||||
int enable_zlib_glz_wrap;
|
|
||||||
|
|
||||||
Ring current_list; // of TreeItem
|
|
||||||
uint32_t current_size;
|
|
||||||
|
|
||||||
uint32_t drawable_count;
|
|
||||||
_Drawable drawables[NUM_DRAWABLES];
|
|
||||||
_Drawable *free_drawables;
|
|
||||||
|
|
||||||
int stream_video;
|
|
||||||
GArray *video_codecs;
|
|
||||||
uint32_t stream_count;
|
|
||||||
Stream streams_buf[NUM_STREAMS];
|
|
||||||
Stream *free_streams;
|
|
||||||
Ring streams;
|
|
||||||
ItemTrace items_trace[NUM_TRACE_ITEMS];
|
|
||||||
uint32_t next_item_trace;
|
|
||||||
uint64_t streams_size_total;
|
|
||||||
|
|
||||||
RedSurface surfaces[NUM_SURFACES];
|
|
||||||
uint32_t n_surfaces;
|
|
||||||
SpiceImageSurfaces image_surfaces;
|
|
||||||
|
|
||||||
ImageCache image_cache;
|
|
||||||
|
|
||||||
int gl_draw_async_count;
|
|
||||||
|
|
||||||
/* TODO: some day unify this, make it more runtime.. */
|
|
||||||
stat_info_t add_stat;
|
|
||||||
stat_info_t exclude_stat;
|
|
||||||
stat_info_t __exclude_stat;
|
|
||||||
#ifdef RED_WORKER_STAT
|
|
||||||
uint32_t add_count;
|
|
||||||
uint32_t add_with_shadow_count;
|
|
||||||
#endif
|
|
||||||
#ifdef RED_STATISTICS
|
|
||||||
uint64_t *cache_hits_counter;
|
|
||||||
uint64_t *add_to_cache_counter;
|
|
||||||
uint64_t *non_cache_counter;
|
|
||||||
#endif
|
|
||||||
ImageEncoderSharedData encoder_shared_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DisplayChannel {
|
|
||||||
CommonGraphicsChannel common; // Must be the first thing
|
|
||||||
|
|
||||||
DisplayChannelPrivate priv[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FOREACH_DCC(_channel, _iter, _data) \
|
#define FOREACH_DCC(_channel, _iter, _data) \
|
||||||
GLIST_FOREACH((_channel ? RED_CHANNEL(_channel)->clients : NULL), \
|
GLIST_FOREACH((_channel ? red_channel_get_clients(RED_CHANNEL(_channel)) : NULL), \
|
||||||
_iter, DisplayChannelClient, _data)
|
_iter, DisplayChannelClient, _data)
|
||||||
|
|
||||||
int display_channel_get_stream_id(DisplayChannel *display, Stream *stream);
|
int display_channel_get_stream_id(DisplayChannel *display, Stream *stream);
|
||||||
@ -262,8 +229,9 @@ void display_channel_set_stream_video (DisplayCha
|
|||||||
int stream_video);
|
int stream_video);
|
||||||
void display_channel_set_video_codecs (DisplayChannel *display,
|
void display_channel_set_video_codecs (DisplayChannel *display,
|
||||||
GArray *video_codecs);
|
GArray *video_codecs);
|
||||||
|
int display_channel_get_stream_video (DisplayChannel *display);
|
||||||
int display_channel_get_streams_timeout (DisplayChannel *display);
|
int display_channel_get_streams_timeout (DisplayChannel *display);
|
||||||
void display_channel_compress_stats_print (const DisplayChannel *display);
|
void display_channel_compress_stats_print (DisplayChannel *display);
|
||||||
void display_channel_compress_stats_reset (DisplayChannel *display);
|
void display_channel_compress_stats_reset (DisplayChannel *display);
|
||||||
void display_channel_surface_unref (DisplayChannel *display,
|
void display_channel_surface_unref (DisplayChannel *display,
|
||||||
uint32_t surface_id);
|
uint32_t surface_id);
|
||||||
@ -415,4 +383,6 @@ static inline void region_add_clip_rects(QRegion *rgn, SpiceClipRects *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* DISPLAY_CHANNEL_H_ */
|
#endif /* DISPLAY_CHANNEL_H_ */
|
||||||
|
|||||||
@ -37,9 +37,11 @@ struct DummyChannelClientPrivate
|
|||||||
|
|
||||||
static int dummy_channel_client_pre_create_validate(RedChannel *channel, RedClient *client)
|
static int dummy_channel_client_pre_create_validate(RedChannel *channel, RedClient *client)
|
||||||
{
|
{
|
||||||
if (red_client_get_channel(client, channel->type, channel->id)) {
|
uint32_t type, id;
|
||||||
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
|
if (red_client_get_channel(client, type, id)) {
|
||||||
spice_printerr("Error client %p: duplicate channel type %d id %d",
|
spice_printerr("Error client %p: duplicate channel type %d id %d",
|
||||||
client, channel->type, channel->id);
|
client, type, id);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -54,6 +56,9 @@ static gboolean dummy_channel_client_initable_init(GInitable *initable,
|
|||||||
RedChannelClient *rcc = RED_CHANNEL_CLIENT(self);
|
RedChannelClient *rcc = RED_CHANNEL_CLIENT(self);
|
||||||
RedClient *client = red_channel_client_get_client(rcc);
|
RedClient *client = red_channel_client_get_client(rcc);
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
uint32_t type, id;
|
||||||
|
|
||||||
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
pthread_mutex_lock(&client->lock);
|
pthread_mutex_lock(&client->lock);
|
||||||
if (!dummy_channel_client_pre_create_validate(channel,
|
if (!dummy_channel_client_pre_create_validate(channel,
|
||||||
client)) {
|
client)) {
|
||||||
@ -61,7 +66,7 @@ static gboolean dummy_channel_client_initable_init(GInitable *initable,
|
|||||||
SPICE_SERVER_ERROR,
|
SPICE_SERVER_ERROR,
|
||||||
SPICE_SERVER_ERROR_FAILED,
|
SPICE_SERVER_ERROR_FAILED,
|
||||||
"Client %p: duplicate channel type %d id %d",
|
"Client %p: duplicate channel type %d id %d",
|
||||||
client, channel->type, channel->id);
|
client, type, id);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,10 +99,12 @@ static void dummy_channel_client_disconnect(RedChannelClient *rcc)
|
|||||||
DummyChannelClient *self = DUMMY_CHANNEL_CLIENT(rcc);
|
DummyChannelClient *self = DUMMY_CHANNEL_CLIENT(rcc);
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
GList *link;
|
GList *link;
|
||||||
|
uint32_t type, id;
|
||||||
|
|
||||||
if (channel && (link = g_list_find(channel->clients, rcc))) {
|
if (channel && (link = g_list_find(red_channel_get_clients(channel), rcc))) {
|
||||||
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
|
spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
|
||||||
channel->type, channel->id);
|
type, id);
|
||||||
red_channel_remove_client(channel, link->data);
|
red_channel_remove_client(channel, link->data);
|
||||||
}
|
}
|
||||||
self->priv->connected = FALSE;
|
self->priv->connected = FALSE;
|
||||||
|
|||||||
49
server/dummy-channel.c
Normal file
49
server/dummy-channel.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/* dummy-channel.c */
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dummy-channel.h"
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(DummyChannel, dummy_channel, RED_TYPE_CHANNEL)
|
||||||
|
|
||||||
|
static void
|
||||||
|
dummy_channel_class_init(DummyChannelClass *klass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dummy_channel_init(DummyChannel *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: red_worker can use this one
|
||||||
|
static void dummy_watch_update_mask(SpiceWatch *watch, int event_mask)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpiceWatch *dummy_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
|
||||||
|
{
|
||||||
|
return NULL; // apparently allowed?
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dummy_watch_remove(SpiceWatch *watch)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: actually, since I also use channel_client_dummym, no need for core. Can be NULL
|
||||||
|
static const SpiceCoreInterface dummy_core = {
|
||||||
|
.watch_update_mask = dummy_watch_update_mask,
|
||||||
|
.watch_add = dummy_watch_add,
|
||||||
|
.watch_remove = dummy_watch_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
RedChannel *dummy_channel_new(RedsState *reds, uint32_t type, uint32_t id)
|
||||||
|
{
|
||||||
|
return g_object_new(TYPE_DUMMY_CHANNEL,
|
||||||
|
"spice-server", reds,
|
||||||
|
"core-interface", &dummy_core,
|
||||||
|
"channel-type", type,
|
||||||
|
"id", id,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
60
server/dummy-channel.h
Normal file
60
server/dummy-channel.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2009-2015 Red Hat, Inc.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DUMMY_CHANNEL_H__
|
||||||
|
#define __DUMMY_CHANNEL_H__
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include "red-channel.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
// TODO: tmp, for channels that don't use RedChannel yet (e.g., snd channel), but
|
||||||
|
// do use the client callbacks. So the channel clients are not connected (the channel doesn't
|
||||||
|
// have list of them, but they do have a link to the channel, and the client has a list of them)
|
||||||
|
|
||||||
|
#define TYPE_DUMMY_CHANNEL dummy_channel_get_type()
|
||||||
|
|
||||||
|
#define DUMMY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DUMMY_CHANNEL, DummyChannel))
|
||||||
|
#define DUMMY_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DUMMY_CHANNEL, DummyChannelClass))
|
||||||
|
#define _IS_DUMMY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_DUMMY_CHANNEL))
|
||||||
|
#define _IS_DUMMY_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DUMMY_CHANNEL))
|
||||||
|
#define DUMMY_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DUMMY_CHANNEL, DummyChannelClass))
|
||||||
|
|
||||||
|
typedef struct DummyChannel DummyChannel;
|
||||||
|
typedef struct DummyChannelClass DummyChannelClass;
|
||||||
|
|
||||||
|
struct DummyChannel
|
||||||
|
{
|
||||||
|
RedChannel parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DummyChannelClass
|
||||||
|
{
|
||||||
|
RedChannelClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType dummy_channel_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
RedChannel *dummy_channel_new(RedsState *reds, uint32_t type, uint32_t id);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __DUMMY_CHANNEL_H__ */
|
||||||
@ -57,6 +57,27 @@
|
|||||||
#define RECEIVE_BUF_SIZE \
|
#define RECEIVE_BUF_SIZE \
|
||||||
(4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
|
(4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
|
||||||
|
|
||||||
|
struct InputsChannel
|
||||||
|
{
|
||||||
|
RedChannel parent;
|
||||||
|
|
||||||
|
uint8_t recv_buf[RECEIVE_BUF_SIZE];
|
||||||
|
VDAgentMouseState mouse_state;
|
||||||
|
int src_during_migrate;
|
||||||
|
SpiceTimer *key_modifiers_timer;
|
||||||
|
|
||||||
|
SpiceKbdInstance *keyboard;
|
||||||
|
SpiceMouseInstance *mouse;
|
||||||
|
SpiceTabletInstance *tablet;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputsChannelClass
|
||||||
|
{
|
||||||
|
RedChannelClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(InputsChannel, inputs_channel, RED_TYPE_CHANNEL)
|
||||||
|
|
||||||
struct SpiceKbdState {
|
struct SpiceKbdState {
|
||||||
uint8_t push_ext_type;
|
uint8_t push_ext_type;
|
||||||
|
|
||||||
@ -105,18 +126,6 @@ RedsState* spice_tablet_state_get_server(SpiceTabletState *st)
|
|||||||
return st->reds;
|
return st->reds;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InputsChannel {
|
|
||||||
RedChannel base;
|
|
||||||
uint8_t recv_buf[RECEIVE_BUF_SIZE];
|
|
||||||
VDAgentMouseState mouse_state;
|
|
||||||
int src_during_migrate;
|
|
||||||
SpiceTimer *key_modifiers_timer;
|
|
||||||
|
|
||||||
SpiceKbdInstance *keyboard;
|
|
||||||
SpiceMouseInstance *mouse;
|
|
||||||
SpiceTabletInstance *tablet;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct RedKeyModifiersPipeItem {
|
typedef struct RedKeyModifiersPipeItem {
|
||||||
RedPipeItem base;
|
RedPipeItem base;
|
||||||
uint8_t modifiers;
|
uint8_t modifiers;
|
||||||
@ -275,7 +284,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
|
|||||||
InputsChannel *inputs_channel = INPUTS_CHANNEL(red_channel_client_get_channel(rcc));
|
InputsChannel *inputs_channel = INPUTS_CHANNEL(red_channel_client_get_channel(rcc));
|
||||||
InputsChannelClient *icc = INPUTS_CHANNEL_CLIENT(rcc);
|
InputsChannelClient *icc = INPUTS_CHANNEL_CLIENT(rcc);
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
RedsState *reds = red_channel_get_server(&inputs_channel->base);
|
RedsState *reds = red_channel_get_server(RED_CHANNEL(inputs_channel));
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SPICE_MSGC_INPUTS_KEY_DOWN: {
|
case SPICE_MSGC_INPUTS_KEY_DOWN: {
|
||||||
@ -359,12 +368,15 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
|
|||||||
reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state);
|
reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state);
|
||||||
} else if (inputs_channel_get_tablet(inputs_channel)) {
|
} else if (inputs_channel_get_tablet(inputs_channel)) {
|
||||||
SpiceTabletInterface *sif;
|
SpiceTabletInterface *sif;
|
||||||
sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)->base.sif, SpiceTabletInterface, base);
|
sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)->base.sif,
|
||||||
sif->wheel(inputs_channel_get_tablet(inputs_channel), dz, RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
|
SpiceTabletInterface, base);
|
||||||
|
sif->wheel(inputs_channel_get_tablet(inputs_channel), dz,
|
||||||
|
RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
|
||||||
}
|
}
|
||||||
} else if (inputs_channel_get_mouse(inputs_channel)) {
|
} else if (inputs_channel_get_mouse(inputs_channel)) {
|
||||||
SpiceMouseInterface *sif;
|
SpiceMouseInterface *sif;
|
||||||
sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif, SpiceMouseInterface, base);
|
sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif,
|
||||||
|
SpiceMouseInterface, base);
|
||||||
sif->motion(inputs_channel_get_mouse(inputs_channel), 0, 0, dz,
|
sif->motion(inputs_channel_get_mouse(inputs_channel), 0, 0, dz,
|
||||||
RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
|
RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
|
||||||
}
|
}
|
||||||
@ -379,12 +391,15 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
|
|||||||
reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state);
|
reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state);
|
||||||
} else if (inputs_channel_get_tablet(inputs_channel)) {
|
} else if (inputs_channel_get_tablet(inputs_channel)) {
|
||||||
SpiceTabletInterface *sif;
|
SpiceTabletInterface *sif;
|
||||||
sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)->base.sif, SpiceTabletInterface, base);
|
sif = SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)->base.sif,
|
||||||
sif->buttons(inputs_channel_get_tablet(inputs_channel), RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
|
SpiceTabletInterface, base);
|
||||||
|
sif->buttons(inputs_channel_get_tablet(inputs_channel),
|
||||||
|
RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
|
||||||
}
|
}
|
||||||
} else if (inputs_channel_get_mouse(inputs_channel)) {
|
} else if (inputs_channel_get_mouse(inputs_channel)) {
|
||||||
SpiceMouseInterface *sif;
|
SpiceMouseInterface *sif;
|
||||||
sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif, SpiceMouseInterface, base);
|
sif = SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif,
|
||||||
|
SpiceMouseInterface, base);
|
||||||
sif->buttons(inputs_channel_get_mouse(inputs_channel),
|
sif->buttons(inputs_channel_get_mouse(inputs_channel),
|
||||||
RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
|
RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
|
||||||
}
|
}
|
||||||
@ -519,11 +534,11 @@ static void inputs_migrate(RedChannelClient *rcc)
|
|||||||
|
|
||||||
static void inputs_channel_push_keyboard_modifiers(InputsChannel *inputs, uint8_t modifiers)
|
static void inputs_channel_push_keyboard_modifiers(InputsChannel *inputs, uint8_t modifiers)
|
||||||
{
|
{
|
||||||
if (!inputs || !red_channel_is_connected(&inputs->base) ||
|
if (!inputs || !red_channel_is_connected(RED_CHANNEL(inputs)) ||
|
||||||
inputs->src_during_migrate) {
|
inputs->src_during_migrate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
red_channel_pipes_new_add_push(&inputs->base,
|
red_channel_pipes_new_add_push(RED_CHANNEL(inputs),
|
||||||
red_inputs_key_modifiers_item_new, (void*)&modifiers);
|
red_inputs_key_modifiers_item_new, (void*)&modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,44 +584,65 @@ static int inputs_channel_handle_migrate_data(RedChannelClient *rcc,
|
|||||||
|
|
||||||
InputsChannel* inputs_channel_new(RedsState *reds)
|
InputsChannel* inputs_channel_new(RedsState *reds)
|
||||||
{
|
{
|
||||||
ChannelCbs channel_cbs = { NULL, };
|
return g_object_new(TYPE_INPUTS_CHANNEL,
|
||||||
|
"spice-server", reds,
|
||||||
|
"core-interface", reds_get_core_interface(reds),
|
||||||
|
"channel-type", (int)SPICE_CHANNEL_INPUTS,
|
||||||
|
"id", 0,
|
||||||
|
"handle-acks", FALSE,
|
||||||
|
"migration-flags",
|
||||||
|
(guint)(SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inputs_channel_constructed(GObject *object)
|
||||||
|
{
|
||||||
ClientCbs client_cbs = { NULL, };
|
ClientCbs client_cbs = { NULL, };
|
||||||
InputsChannel *inputs;
|
InputsChannel *self = INPUTS_CHANNEL(object);
|
||||||
|
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
|
||||||
|
|
||||||
channel_cbs.config_socket = inputs_channel_config_socket;
|
G_OBJECT_CLASS(inputs_channel_parent_class)->constructed(object);
|
||||||
channel_cbs.on_disconnect = inputs_channel_on_disconnect;
|
|
||||||
channel_cbs.send_item = inputs_channel_send_item;
|
|
||||||
channel_cbs.alloc_recv_buf = inputs_channel_alloc_msg_rcv_buf;
|
|
||||||
channel_cbs.release_recv_buf = inputs_channel_release_msg_rcv_buf;
|
|
||||||
channel_cbs.handle_migrate_data = inputs_channel_handle_migrate_data;
|
|
||||||
channel_cbs.handle_migrate_flush_mark = inputs_channel_handle_migrate_flush_mark;
|
|
||||||
|
|
||||||
inputs = INPUTS_CHANNEL(red_channel_create_parser(
|
|
||||||
sizeof(InputsChannel),
|
|
||||||
reds,
|
|
||||||
reds_get_core_interface(reds),
|
|
||||||
SPICE_CHANNEL_INPUTS, 0,
|
|
||||||
FALSE, /* handle_acks */
|
|
||||||
spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL),
|
|
||||||
inputs_channel_handle_parsed,
|
|
||||||
&channel_cbs,
|
|
||||||
SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER));
|
|
||||||
|
|
||||||
if (!inputs) {
|
|
||||||
spice_error("failed to allocate Inputs Channel");
|
|
||||||
}
|
|
||||||
|
|
||||||
client_cbs.connect = inputs_connect;
|
client_cbs.connect = inputs_connect;
|
||||||
client_cbs.migrate = inputs_migrate;
|
client_cbs.migrate = inputs_migrate;
|
||||||
red_channel_register_client_cbs(&inputs->base, &client_cbs, NULL);
|
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
|
||||||
|
|
||||||
red_channel_set_cap(&inputs->base, SPICE_INPUTS_CAP_KEY_SCANCODE);
|
red_channel_set_cap(RED_CHANNEL(self), SPICE_INPUTS_CAP_KEY_SCANCODE);
|
||||||
reds_register_channel(reds, &inputs->base);
|
reds_register_channel(reds, RED_CHANNEL(self));
|
||||||
|
|
||||||
if (!(inputs->key_modifiers_timer = reds_core_timer_add(reds, key_modifiers_sender, inputs))) {
|
self->key_modifiers_timer = reds_core_timer_add(reds, key_modifiers_sender, self);
|
||||||
|
if (!self->key_modifiers_timer) {
|
||||||
spice_error("key modifiers timer create failed");
|
spice_error("key modifiers timer create failed");
|
||||||
}
|
}
|
||||||
return inputs;
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inputs_channel_init(InputsChannel *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
inputs_channel_class_init(InputsChannelClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->constructed = inputs_channel_constructed;
|
||||||
|
|
||||||
|
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
|
||||||
|
channel_class->handle_parsed = inputs_channel_handle_parsed;
|
||||||
|
|
||||||
|
/* channel callbacks */
|
||||||
|
channel_class->config_socket = inputs_channel_config_socket;
|
||||||
|
channel_class->on_disconnect = inputs_channel_on_disconnect;
|
||||||
|
channel_class->send_item = inputs_channel_send_item;
|
||||||
|
channel_class->alloc_recv_buf = inputs_channel_alloc_msg_rcv_buf;
|
||||||
|
channel_class->release_recv_buf = inputs_channel_release_msg_rcv_buf;
|
||||||
|
channel_class->handle_migrate_data = inputs_channel_handle_migrate_data;
|
||||||
|
channel_class->handle_migrate_flush_mark = inputs_channel_handle_migrate_flush_mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SpiceKbdInstance* inputs_channel_get_keyboard(InputsChannel *inputs)
|
static SpiceKbdInstance* inputs_channel_get_keyboard(InputsChannel *inputs)
|
||||||
@ -621,7 +657,7 @@ int inputs_channel_set_keyboard(InputsChannel *inputs, SpiceKbdInstance *keyboar
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
inputs->keyboard = keyboard;
|
inputs->keyboard = keyboard;
|
||||||
inputs->keyboard->st = spice_kbd_state_new(red_channel_get_server(&inputs->base));
|
inputs->keyboard->st = spice_kbd_state_new(red_channel_get_server(RED_CHANNEL(inputs)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,15 +22,30 @@
|
|||||||
// This include should only be used by reds.c and inputs-channel.c
|
// This include should only be used by reds.c and inputs-channel.c
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <glib-object.h>
|
||||||
#include <spice/vd_agent.h>
|
#include <spice/vd_agent.h>
|
||||||
|
|
||||||
#include "red-channel.h"
|
#include "red-channel.h"
|
||||||
|
|
||||||
#define INPUTS_CHANNEL(channel) ((InputsChannel*)(channel))
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define TYPE_INPUTS_CHANNEL inputs_channel_get_type()
|
||||||
|
|
||||||
|
#define INPUTS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_INPUTS_CHANNEL, InputsChannel))
|
||||||
|
#define INPUTS_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), TYPE_INPUTS_CHANNEL, InputsChannelClass))
|
||||||
|
#define INPUTS_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_INPUTS_CHANNEL))
|
||||||
|
#define INPUTS_IS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_INPUTS_CHANNEL))
|
||||||
|
#define INPUTS_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_INPUTS_CHANNEL, InputsChannelClass))
|
||||||
|
|
||||||
typedef struct InputsChannel InputsChannel;
|
typedef struct InputsChannel InputsChannel;
|
||||||
|
typedef struct InputsChannelClass InputsChannelClass;
|
||||||
|
|
||||||
|
GType inputs_channel_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
InputsChannel* inputs_channel_new(RedsState *reds);
|
InputsChannel* inputs_channel_new(RedsState *reds);
|
||||||
|
|
||||||
const VDAgentMouseState *inputs_channel_get_mouse_state(InputsChannel *inputs);
|
const VDAgentMouseState *inputs_channel_get_mouse_state(InputsChannel *inputs);
|
||||||
void inputs_channel_on_keyboard_leds_change(InputsChannel *inputs, uint8_t leds);
|
void inputs_channel_on_keyboard_leds_change(InputsChannel *inputs, uint8_t leds);
|
||||||
void inputs_channel_set_tablet_logical_size(InputsChannel *inputs, int x_res, int y_res);
|
void inputs_channel_set_tablet_logical_size(InputsChannel *inputs, int x_res, int y_res);
|
||||||
@ -44,4 +59,6 @@ RedsState* spice_tablet_state_get_server(SpiceTabletState *dev);
|
|||||||
RedsState* spice_kbd_state_get_server(SpiceKbdState *dev);
|
RedsState* spice_kbd_state_get_server(SpiceKbdState *dev);
|
||||||
gboolean inputs_channel_is_src_during_migrate(InputsChannel *inputs);
|
gboolean inputs_channel_is_src_during_migrate(InputsChannel *inputs);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -435,7 +435,7 @@ void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
|
|||||||
spice_printerr("client %p connected: %d seamless %d", client, success, seamless);
|
spice_printerr("client %p connected: %d seamless %d", client, success, seamless);
|
||||||
if (mcc->priv->mig_wait_connect) {
|
if (mcc->priv->mig_wait_connect) {
|
||||||
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
|
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
|
||||||
MainChannel *main_channel = SPICE_CONTAINEROF(channel, MainChannel, base);
|
MainChannel *main_channel = MAIN_CHANNEL(channel);
|
||||||
|
|
||||||
mcc->priv->mig_wait_connect = FALSE;
|
mcc->priv->mig_wait_connect = FALSE;
|
||||||
mcc->priv->mig_connect_ok = success;
|
mcc->priv->mig_connect_ok = success;
|
||||||
@ -453,7 +453,7 @@ void main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient *mcc,
|
|||||||
uint32_t src_version)
|
uint32_t src_version)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
|
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
|
||||||
if (reds_on_migrate_dst_set_seamless(channel->reds, mcc, src_version)) {
|
if (reds_on_migrate_dst_set_seamless(red_channel_get_server(channel), mcc, src_version)) {
|
||||||
mcc->priv->seamless_mig_dst = TRUE;
|
mcc->priv->seamless_mig_dst = TRUE;
|
||||||
red_channel_client_pipe_add_empty_msg(RED_CHANNEL_CLIENT(mcc),
|
red_channel_client_pipe_add_empty_msg(RED_CHANNEL_CLIENT(mcc),
|
||||||
SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
|
SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK);
|
||||||
@ -553,7 +553,7 @@ void main_channel_client_migrate_dst_complete(MainChannelClient *mcc)
|
|||||||
if (mcc->priv->mig_wait_prev_complete) {
|
if (mcc->priv->mig_wait_prev_complete) {
|
||||||
if (mcc->priv->mig_wait_prev_try_seamless) {
|
if (mcc->priv->mig_wait_prev_try_seamless) {
|
||||||
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
|
RedChannel *channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
|
||||||
spice_assert(g_list_length(channel->clients) == 1);
|
spice_assert(red_channel_get_n_clients(channel) == 1);
|
||||||
red_channel_client_pipe_add_type(RED_CHANNEL_CLIENT(mcc),
|
red_channel_client_pipe_add_type(RED_CHANNEL_CLIENT(mcc),
|
||||||
RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS);
|
RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_BEGIN_SEAMLESS);
|
||||||
} else {
|
} else {
|
||||||
@ -609,9 +609,11 @@ static void do_ping_client(MainChannelClient *mcc,
|
|||||||
if (has_interval && interval > 0) {
|
if (has_interval && interval > 0) {
|
||||||
mcc->priv->ping_interval = interval * MSEC_PER_SEC;
|
mcc->priv->ping_interval = interval * MSEC_PER_SEC;
|
||||||
}
|
}
|
||||||
reds_core_timer_start(channel->reds, mcc->priv->ping_timer, mcc->priv->ping_interval);
|
reds_core_timer_start(red_channel_get_server(channel),
|
||||||
|
mcc->priv->ping_timer, mcc->priv->ping_interval);
|
||||||
} else if (!strcmp(opt, "off")) {
|
} else if (!strcmp(opt, "off")) {
|
||||||
reds_core_timer_cancel(channel->reds, mcc->priv->ping_timer);
|
reds_core_timer_cancel(red_channel_get_server(channel),
|
||||||
|
mcc->priv->ping_timer);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -624,11 +626,13 @@ static void ping_timer_cb(void *opaque)
|
|||||||
|
|
||||||
if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(mcc))) {
|
if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(mcc))) {
|
||||||
spice_printerr("not connected to peer, ping off");
|
spice_printerr("not connected to peer, ping off");
|
||||||
reds_core_timer_cancel(channel->reds, mcc->priv->ping_timer);
|
reds_core_timer_cancel(red_channel_get_server(channel),
|
||||||
|
mcc->priv->ping_timer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
do_ping_client(mcc, NULL, 0, 0);
|
do_ping_client(mcc, NULL, 0, 0);
|
||||||
reds_core_timer_start(channel->reds, mcc->priv->ping_timer, mcc->priv->ping_interval);
|
reds_core_timer_start(red_channel_get_server(channel),
|
||||||
|
mcc->priv->ping_timer, mcc->priv->ping_interval);
|
||||||
}
|
}
|
||||||
#endif /* RED_STATISTICS */
|
#endif /* RED_STATISTICS */
|
||||||
|
|
||||||
@ -693,7 +697,8 @@ uint64_t main_channel_client_get_roundtrip_ms(MainChannelClient *mcc)
|
|||||||
void main_channel_client_migrate(RedChannelClient *rcc)
|
void main_channel_client_migrate(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
reds_on_main_channel_migrate(channel->reds, MAIN_CHANNEL_CLIENT(rcc));
|
reds_on_main_channel_migrate(red_channel_get_server(channel),
|
||||||
|
MAIN_CHANNEL_CLIENT(rcc));
|
||||||
red_channel_client_default_migrate(rcc);
|
red_channel_client_default_migrate(rcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,7 +759,7 @@ static void main_channel_marshall_channels(RedChannelClient *rcc,
|
|||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST, item);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST, item);
|
||||||
channels_info = reds_msg_channels_new(channel->reds);
|
channels_info = reds_msg_channels_new(red_channel_get_server(channel));
|
||||||
spice_marshall_msg_main_channels_list(m, channels_info);
|
spice_marshall_msg_main_channels_list(m, channels_info);
|
||||||
free(channels_info);
|
free(channels_info);
|
||||||
}
|
}
|
||||||
@ -829,7 +834,8 @@ static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
|
|||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
|
||||||
reds_marshall_migrate_data(channel->reds, m); // TODO: from reds split. ugly separation.
|
// TODO: from reds split. ugly separation.
|
||||||
|
reds_marshall_migrate_data(red_channel_get_server(channel), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void main_channel_marshall_init(RedChannelClient *rcc,
|
static void main_channel_marshall_init(RedChannelClient *rcc,
|
||||||
@ -847,7 +853,7 @@ static void main_channel_marshall_init(RedChannelClient *rcc,
|
|||||||
if (item->is_client_mouse_allowed) {
|
if (item->is_client_mouse_allowed) {
|
||||||
init.supported_mouse_modes |= SPICE_MOUSE_MODE_CLIENT;
|
init.supported_mouse_modes |= SPICE_MOUSE_MODE_CLIENT;
|
||||||
}
|
}
|
||||||
init.agent_connected = reds_has_vdagent(channel->reds);
|
init.agent_connected = reds_has_vdagent(red_channel_get_server(channel));
|
||||||
init.agent_tokens = REDS_AGENT_WINDOW_SIZE;
|
init.agent_tokens = REDS_AGENT_WINDOW_SIZE;
|
||||||
init.multi_media_time = item->multi_media_time;
|
init.multi_media_time = item->multi_media_time;
|
||||||
init.ram_hint = item->ram_hint;
|
init.ram_hint = item->ram_hint;
|
||||||
@ -891,11 +897,9 @@ static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, RedChannelCl
|
|||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
SpiceMsgMainMigrationBegin migrate;
|
SpiceMsgMainMigrationBegin migrate;
|
||||||
MainChannel *main_ch;
|
|
||||||
|
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN, item);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN, item);
|
||||||
main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
|
main_channel_fill_migrate_dst_info(MAIN_CHANNEL(channel), &migrate.dst_info);
|
||||||
main_channel_fill_migrate_dst_info(main_ch, &migrate.dst_info);
|
|
||||||
spice_marshall_msg_main_migrate_begin(m, &migrate);
|
spice_marshall_msg_main_migrate_begin(m, &migrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -905,11 +909,9 @@ static void main_channel_marshall_migrate_begin_seamless(SpiceMarshaller *m,
|
|||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
SpiceMsgMainMigrateBeginSeamless migrate_seamless;
|
SpiceMsgMainMigrateBeginSeamless migrate_seamless;
|
||||||
MainChannel *main_ch;
|
|
||||||
|
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS, item);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS, item);
|
||||||
main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
|
main_channel_fill_migrate_dst_info(MAIN_CHANNEL(channel), &migrate_seamless.dst_info);
|
||||||
main_channel_fill_migrate_dst_info(main_ch, &migrate_seamless.dst_info);
|
|
||||||
migrate_seamless.src_mig_version = SPICE_MIGRATION_PROTOCOL_VERSION;
|
migrate_seamless.src_mig_version = SPICE_MIGRATION_PROTOCOL_VERSION;
|
||||||
spice_marshall_msg_main_migrate_begin_seamless(m, &migrate_seamless);
|
spice_marshall_msg_main_migrate_begin_seamless(m, &migrate_seamless);
|
||||||
}
|
}
|
||||||
@ -935,7 +937,7 @@ static void main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelC
|
|||||||
|
|
||||||
spice_printerr("");
|
spice_printerr("");
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, item);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, item);
|
||||||
main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
|
main_ch = MAIN_CHANNEL(channel);
|
||||||
mig_target = main_channel_get_migration_target(main_ch);
|
mig_target = main_channel_get_migration_target(main_ch);
|
||||||
migrate.port = mig_target->port;
|
migrate.port = mig_target->port;
|
||||||
migrate.sport = mig_target->sport;
|
migrate.sport = mig_target->sport;
|
||||||
|
|||||||
@ -27,9 +27,30 @@
|
|||||||
#include "main-channel.h"
|
#include "main-channel.h"
|
||||||
#include "main-channel-client.h"
|
#include "main-channel-client.h"
|
||||||
|
|
||||||
|
// approximate max receive message size for main channel
|
||||||
|
#define MAIN_CHANNEL_RECEIVE_BUF_SIZE \
|
||||||
|
(4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
|
||||||
|
|
||||||
|
struct MainChannel
|
||||||
|
{
|
||||||
|
RedChannel parent;
|
||||||
|
|
||||||
|
uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
|
||||||
|
// TODO: add refs and release (afrer all clients completed migration in one way or the other?)
|
||||||
|
RedsMigSpice mig_target;
|
||||||
|
int num_clients_mig_wait;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MainChannelClass
|
||||||
|
{
|
||||||
|
RedChannelClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(MainChannel, main_channel, RED_TYPE_CHANNEL)
|
||||||
|
|
||||||
int main_channel_is_connected(MainChannel *main_chan)
|
int main_channel_is_connected(MainChannel *main_chan)
|
||||||
{
|
{
|
||||||
return red_channel_is_connected(&main_chan->base);
|
return red_channel_is_connected(RED_CHANNEL(main_chan));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -76,27 +97,29 @@ void main_channel_push_mouse_mode(MainChannel *main_chan, int current_mode,
|
|||||||
.is_client_mouse_allowed=is_client_mouse_allowed,
|
.is_client_mouse_allowed=is_client_mouse_allowed,
|
||||||
};
|
};
|
||||||
|
|
||||||
red_channel_pipes_new_add_push(&main_chan->base,
|
red_channel_pipes_new_add_push(RED_CHANNEL(main_chan),
|
||||||
main_mouse_mode_item_new, &info);
|
main_mouse_mode_item_new, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_channel_push_agent_connected(MainChannel *main_chan)
|
void main_channel_push_agent_connected(MainChannel *main_chan)
|
||||||
{
|
{
|
||||||
if (red_channel_test_remote_cap(&main_chan->base, SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
|
if (red_channel_test_remote_cap(RED_CHANNEL(main_chan),
|
||||||
red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS);
|
SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
|
||||||
|
red_channel_pipes_add_type(RED_CHANNEL(main_chan),
|
||||||
|
RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS);
|
||||||
} else {
|
} else {
|
||||||
red_channel_pipes_add_empty_msg(&main_chan->base, SPICE_MSG_MAIN_AGENT_CONNECTED);
|
red_channel_pipes_add_empty_msg(RED_CHANNEL(main_chan), SPICE_MSG_MAIN_AGENT_CONNECTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_channel_push_agent_disconnected(MainChannel *main_chan)
|
void main_channel_push_agent_disconnected(MainChannel *main_chan)
|
||||||
{
|
{
|
||||||
red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED);
|
red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void main_channel_push_migrate_data_item(MainChannel *main_chan)
|
static void main_channel_push_migrate_data_item(MainChannel *main_chan)
|
||||||
{
|
{
|
||||||
red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA);
|
red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int main_channel_handle_migrate_data(RedChannelClient *rcc,
|
static int main_channel_handle_migrate_data(RedChannelClient *rcc,
|
||||||
@ -107,7 +130,7 @@ static int main_channel_handle_migrate_data(RedChannelClient *rcc,
|
|||||||
SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader *)message;
|
SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader *)message;
|
||||||
|
|
||||||
/* not supported with multi-clients */
|
/* not supported with multi-clients */
|
||||||
spice_assert(g_list_length(channel->clients) == 1);
|
spice_assert(red_channel_get_n_clients(channel) == 1);
|
||||||
|
|
||||||
if (size < sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataMain)) {
|
if (size < sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataMain)) {
|
||||||
spice_printerr("bad message size %u", size);
|
spice_printerr("bad message size %u", size);
|
||||||
@ -119,7 +142,9 @@ static int main_channel_handle_migrate_data(RedChannelClient *rcc,
|
|||||||
spice_error("bad header");
|
spice_error("bad header");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return reds_handle_migrate_data(channel->reds, mcc, (SpiceMigrateDataMain *)(header + 1), size);
|
return reds_handle_migrate_data(red_channel_get_server(channel), mcc,
|
||||||
|
(SpiceMigrateDataMain *)(header + 1),
|
||||||
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_channel_push_multi_media_time(MainChannel *main_chan, int time)
|
void main_channel_push_multi_media_time(MainChannel *main_chan, int time)
|
||||||
@ -128,7 +153,7 @@ void main_channel_push_multi_media_time(MainChannel *main_chan, int time)
|
|||||||
.time = time,
|
.time = time,
|
||||||
};
|
};
|
||||||
|
|
||||||
red_channel_pipes_new_add_push(&main_chan->base,
|
red_channel_pipes_new_add_push(RED_CHANNEL(main_chan),
|
||||||
main_multi_media_time_item_new, &info);
|
main_multi_media_time_item_new, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,15 +175,16 @@ static void main_channel_fill_mig_target(MainChannel *main_channel, RedsMigSpice
|
|||||||
void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice *mig_target)
|
void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice *mig_target)
|
||||||
{
|
{
|
||||||
main_channel_fill_mig_target(main_chan, mig_target);
|
main_channel_fill_mig_target(main_chan, mig_target);
|
||||||
red_channel_pipes_add_type(&main_chan->base, RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
|
red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type,
|
static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type,
|
||||||
void *message)
|
void *message)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
|
MainChannel *main_chan = MAIN_CHANNEL(channel);
|
||||||
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
|
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
|
||||||
|
RedsState *reds = red_channel_get_server(channel);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SPICE_MSGC_MAIN_AGENT_START: {
|
case SPICE_MSGC_MAIN_AGENT_START: {
|
||||||
@ -169,18 +195,18 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
tokens = (SpiceMsgcMainAgentStart *)message;
|
tokens = (SpiceMsgcMainAgentStart *)message;
|
||||||
reds_on_main_agent_start(channel->reds, mcc, tokens->num_tokens);
|
reds_on_main_agent_start(reds, mcc, tokens->num_tokens);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPICE_MSGC_MAIN_AGENT_DATA: {
|
case SPICE_MSGC_MAIN_AGENT_DATA: {
|
||||||
reds_on_main_agent_data(channel->reds, mcc, message, size);
|
reds_on_main_agent_data(reds, mcc, message, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPICE_MSGC_MAIN_AGENT_TOKEN: {
|
case SPICE_MSGC_MAIN_AGENT_TOKEN: {
|
||||||
SpiceMsgcMainAgentTokens *tokens;
|
SpiceMsgcMainAgentTokens *tokens;
|
||||||
|
|
||||||
tokens = (SpiceMsgcMainAgentTokens *)message;
|
tokens = (SpiceMsgcMainAgentTokens *)message;
|
||||||
reds_on_main_agent_tokens(channel->reds, mcc, tokens->num_tokens);
|
reds_on_main_agent_tokens(reds, mcc, tokens->num_tokens);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPICE_MSGC_MAIN_ATTACH_CHANNELS:
|
case SPICE_MSGC_MAIN_ATTACH_CHANNELS:
|
||||||
@ -204,7 +230,7 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
|
|||||||
((SpiceMsgcMainMigrateDstDoSeamless *)message)->src_version);
|
((SpiceMsgcMainMigrateDstDoSeamless *)message)->src_version);
|
||||||
break;
|
break;
|
||||||
case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
|
case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
|
||||||
reds_on_main_mouse_mode_request(channel->reds, message, size);
|
reds_on_main_mouse_mode_request(reds, message, size);
|
||||||
break;
|
break;
|
||||||
case SPICE_MSGC_PONG: {
|
case SPICE_MSGC_PONG: {
|
||||||
main_channel_client_handle_pong(mcc, (SpiceMsgPing *)message, size);
|
main_channel_client_handle_pong(mcc, (SpiceMsgPing *)message, size);
|
||||||
@ -226,11 +252,11 @@ static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
|
|||||||
uint32_t size)
|
uint32_t size)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel, base);
|
MainChannel *main_chan = MAIN_CHANNEL(channel);
|
||||||
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
|
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
|
||||||
|
|
||||||
if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
|
if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
|
||||||
return reds_get_agent_data_buffer(channel->reds, mcc, size);
|
return reds_get_agent_data_buffer(red_channel_get_server(channel), mcc, size);
|
||||||
} else {
|
} else {
|
||||||
return main_chan->recv_buf;
|
return main_chan->recv_buf;
|
||||||
}
|
}
|
||||||
@ -243,7 +269,7 @@ static void main_channel_release_msg_rcv_buf(RedChannelClient *rcc,
|
|||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
|
if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
|
||||||
reds_release_agent_data_buffer(channel->reds, msg);
|
reds_release_agent_data_buffer(red_channel_get_server(channel), msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,8 +282,7 @@ static int main_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
|
|||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
spice_debug(NULL);
|
spice_debug(NULL);
|
||||||
main_channel_push_migrate_data_item(SPICE_CONTAINEROF(channel,
|
main_channel_push_migrate_data_item(MAIN_CHANNEL(channel));
|
||||||
MainChannel, base));
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,12 +307,14 @@ MainChannelClient *main_channel_link(MainChannel *channel, RedClient *client,
|
|||||||
|
|
||||||
int main_channel_getsockname(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen)
|
int main_channel_getsockname(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen)
|
||||||
{
|
{
|
||||||
return main_chan ? getsockname(red_channel_get_first_socket(&main_chan->base), sa, salen) : -1;
|
return main_chan ?
|
||||||
|
getsockname(red_channel_get_first_socket(RED_CHANNEL(main_chan)), sa, salen) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main_channel_getpeername(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen)
|
int main_channel_getpeername(MainChannel *main_chan, struct sockaddr *sa, socklen_t *salen)
|
||||||
{
|
{
|
||||||
return main_chan ? getpeername(red_channel_get_first_socket(&main_chan->base), sa, salen) : -1;
|
return main_chan ?
|
||||||
|
getpeername(red_channel_get_first_socket(RED_CHANNEL(main_chan)), sa, salen) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ? shouldn't it disonnect all clients? or shutdown all main_channels?
|
// TODO: ? shouldn't it disonnect all clients? or shutdown all main_channels?
|
||||||
@ -295,42 +322,64 @@ void main_channel_close(MainChannel *main_chan)
|
|||||||
{
|
{
|
||||||
int socketfd;
|
int socketfd;
|
||||||
|
|
||||||
if (main_chan && (socketfd = red_channel_get_first_socket(&main_chan->base)) != -1) {
|
if (main_chan && (socketfd = red_channel_get_first_socket(RED_CHANNEL(main_chan))) != -1) {
|
||||||
close(socketfd);
|
close(socketfd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainChannel* main_channel_new(RedsState *reds)
|
MainChannel* main_channel_new(RedsState *reds)
|
||||||
{
|
{
|
||||||
RedChannel *channel;
|
|
||||||
ChannelCbs channel_cbs = { NULL, };
|
|
||||||
ClientCbs client_cbs = {NULL, };
|
|
||||||
|
|
||||||
channel_cbs.config_socket = main_channel_config_socket;
|
|
||||||
channel_cbs.on_disconnect = main_channel_client_on_disconnect;
|
|
||||||
channel_cbs.send_item = main_channel_client_send_item;
|
|
||||||
channel_cbs.alloc_recv_buf = main_channel_alloc_msg_rcv_buf;
|
|
||||||
channel_cbs.release_recv_buf = main_channel_release_msg_rcv_buf;
|
|
||||||
channel_cbs.handle_migrate_flush_mark = main_channel_handle_migrate_flush_mark;
|
|
||||||
channel_cbs.handle_migrate_data = main_channel_handle_migrate_data;
|
|
||||||
|
|
||||||
// TODO: set the migration flag of the channel
|
// TODO: set the migration flag of the channel
|
||||||
channel = red_channel_create_parser(sizeof(MainChannel), reds,
|
return g_object_new(TYPE_MAIN_CHANNEL,
|
||||||
reds_get_core_interface(reds),
|
"spice-server", reds,
|
||||||
SPICE_CHANNEL_MAIN, 0,
|
"core-interface", reds_get_core_interface(reds),
|
||||||
FALSE, /* handle_acks */
|
"channel-type", (gint)SPICE_CHANNEL_MAIN,
|
||||||
spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL),
|
"id", 0,
|
||||||
main_channel_handle_parsed,
|
"handle-acks", FALSE, /* handle_acks */
|
||||||
&channel_cbs,
|
"migration-flags",
|
||||||
SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
|
(SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
|
||||||
spice_assert(channel);
|
NULL);
|
||||||
red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
|
}
|
||||||
red_channel_set_cap(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
|
|
||||||
|
static void
|
||||||
|
main_channel_constructed(GObject *object)
|
||||||
|
{
|
||||||
|
MainChannel *self = MAIN_CHANNEL(object);
|
||||||
|
ClientCbs client_cbs = { NULL, };
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(main_channel_parent_class)->constructed(object);
|
||||||
|
|
||||||
|
red_channel_set_cap(RED_CHANNEL(self), SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
|
||||||
|
red_channel_set_cap(RED_CHANNEL(self), SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
|
||||||
|
|
||||||
client_cbs.migrate = main_channel_client_migrate;
|
client_cbs.migrate = main_channel_client_migrate;
|
||||||
red_channel_register_client_cbs(channel, &client_cbs, NULL);
|
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
return MAIN_CHANNEL(channel);
|
static void
|
||||||
|
main_channel_init(MainChannel *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
main_channel_class_init(MainChannelClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->constructed = main_channel_constructed;
|
||||||
|
|
||||||
|
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL);
|
||||||
|
channel_class->handle_parsed = main_channel_handle_parsed;
|
||||||
|
|
||||||
|
/* channel callbacks */
|
||||||
|
channel_class->config_socket = main_channel_config_socket;
|
||||||
|
channel_class->on_disconnect = main_channel_client_on_disconnect;
|
||||||
|
channel_class->send_item = main_channel_client_send_item;
|
||||||
|
channel_class->alloc_recv_buf = main_channel_alloc_msg_rcv_buf;
|
||||||
|
channel_class->release_recv_buf = main_channel_release_msg_rcv_buf;
|
||||||
|
channel_class->handle_migrate_flush_mark = main_channel_handle_migrate_flush_mark;
|
||||||
|
channel_class->handle_migrate_data = main_channel_handle_migrate_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int main_channel_connect_semi_seamless(MainChannel *main_channel)
|
static int main_channel_connect_semi_seamless(MainChannel *main_channel)
|
||||||
@ -351,7 +400,7 @@ static int main_channel_connect_seamless(MainChannel *main_channel)
|
|||||||
GListIter iter;
|
GListIter iter;
|
||||||
RedChannelClient *rcc;
|
RedChannelClient *rcc;
|
||||||
|
|
||||||
spice_assert(g_list_length(main_channel->base.clients) == 1);
|
spice_assert(red_channel_get_n_clients(RED_CHANNEL(main_channel)) == 1);
|
||||||
|
|
||||||
FOREACH_CLIENT(main_channel, iter, rcc) {
|
FOREACH_CLIENT(main_channel, iter, rcc) {
|
||||||
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
|
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
|
||||||
@ -375,8 +424,10 @@ int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_ta
|
|||||||
return main_channel_connect_semi_seamless(main_channel);
|
return main_channel_connect_semi_seamless(main_channel);
|
||||||
} else {
|
} else {
|
||||||
RedChannelClient *rcc;
|
RedChannelClient *rcc;
|
||||||
|
GList *clients = red_channel_get_clients(RED_CHANNEL(main_channel));
|
||||||
|
|
||||||
rcc = g_list_nth_data(main_channel->base.clients, 0);
|
/* just test the first one */
|
||||||
|
rcc = g_list_nth_data(clients, 0);
|
||||||
|
|
||||||
if (!red_channel_client_test_remote_cap(rcc,
|
if (!red_channel_client_test_remote_cap(rcc,
|
||||||
SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) {
|
SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) {
|
||||||
@ -408,7 +459,7 @@ int main_channel_migrate_src_complete(MainChannel *main_chan, int success)
|
|||||||
|
|
||||||
spice_printerr("");
|
spice_printerr("");
|
||||||
|
|
||||||
if (!main_chan->base.clients) {
|
if (!red_channel_get_clients(RED_CHANNEL(main_chan))) {
|
||||||
spice_printerr("no peer connected");
|
spice_printerr("no peer connected");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,22 +19,34 @@
|
|||||||
#define __MAIN_CHANNEL_H__
|
#define __MAIN_CHANNEL_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <glib-object.h>
|
||||||
#include <spice/vd_agent.h>
|
#include <spice/vd_agent.h>
|
||||||
#include <common/marshaller.h>
|
#include <common/marshaller.h>
|
||||||
|
|
||||||
#include "red-channel.h"
|
#include "red-channel.h"
|
||||||
|
|
||||||
#define MAIN_CHANNEL(channel) ((MainChannel*)(channel))
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define TYPE_MAIN_CHANNEL main_channel_get_type()
|
||||||
|
|
||||||
|
#define MAIN_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_MAIN_CHANNEL, MainChannel))
|
||||||
|
#define MAIN_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), TYPE_MAIN_CHANNEL, MainChannelClass))
|
||||||
|
#define IS_MAIN_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_MAIN_CHANNEL))
|
||||||
|
#define IS_MAIN_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_MAIN_CHANNEL))
|
||||||
|
#define MAIN_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_MAIN_CHANNEL, MainChannelClass))
|
||||||
|
|
||||||
|
typedef struct MainChannel MainChannel;
|
||||||
|
typedef struct MainChannelClass MainChannelClass;
|
||||||
|
|
||||||
|
GType main_channel_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
// TODO: Defines used to calculate receive buffer size, and also by reds.c
|
// TODO: Defines used to calculate receive buffer size, and also by reds.c
|
||||||
// other options: is to make a reds_main_consts.h, to duplicate defines.
|
// other options: is to make a reds_main_consts.h, to duplicate defines.
|
||||||
#define REDS_AGENT_WINDOW_SIZE 10
|
#define REDS_AGENT_WINDOW_SIZE 10
|
||||||
#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1
|
#define REDS_NUM_INTERNAL_AGENT_MESSAGES 1
|
||||||
|
|
||||||
// approximate max receive message size for main channel
|
|
||||||
#define MAIN_CHANNEL_RECEIVE_BUF_SIZE \
|
|
||||||
(4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
|
|
||||||
|
|
||||||
struct RedsMigSpice {
|
struct RedsMigSpice {
|
||||||
char *host;
|
char *host;
|
||||||
char *cert_subject;
|
char *cert_subject;
|
||||||
@ -43,14 +55,6 @@ struct RedsMigSpice {
|
|||||||
};
|
};
|
||||||
typedef struct RedsMigSpice RedsMigSpice;
|
typedef struct RedsMigSpice RedsMigSpice;
|
||||||
|
|
||||||
typedef struct MainChannel {
|
|
||||||
RedChannel base;
|
|
||||||
uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
|
|
||||||
RedsMigSpice mig_target; // TODO: add refs and release (afrer all clients completed migration in one way or the other?)
|
|
||||||
int num_clients_mig_wait;
|
|
||||||
} MainChannel;
|
|
||||||
|
|
||||||
|
|
||||||
MainChannel *main_channel_new(RedsState *reds);
|
MainChannel *main_channel_new(RedsState *reds);
|
||||||
RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t link_id);
|
RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t link_id);
|
||||||
/* This is a 'clone' from the reds.h Channel.link callback to allow passing link_id */
|
/* This is a 'clone' from the reds.h Channel.link callback to allow passing link_id */
|
||||||
@ -83,4 +87,6 @@ int main_channel_migrate_src_complete(MainChannel *main_chan, int success);
|
|||||||
void main_channel_on_migrate_connected(MainChannel *main_channel,
|
void main_channel_on_migrate_connected(MainChannel *main_channel,
|
||||||
gboolean success, gboolean seamless);
|
gboolean success, gboolean seamless);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -21,6 +21,25 @@
|
|||||||
#include "red-channel.h"
|
#include "red-channel.h"
|
||||||
#include "red-channel-client.h"
|
#include "red-channel-client.h"
|
||||||
|
|
||||||
|
typedef struct RedChannelClientLatencyMonitor {
|
||||||
|
int state;
|
||||||
|
uint64_t last_pong_time;
|
||||||
|
SpiceTimer *timer;
|
||||||
|
uint32_t id;
|
||||||
|
int tcp_nodelay;
|
||||||
|
int warmup_was_sent;
|
||||||
|
|
||||||
|
int64_t roundtrip;
|
||||||
|
} RedChannelClientLatencyMonitor;
|
||||||
|
|
||||||
|
typedef struct RedChannelClientConnectivityMonitor {
|
||||||
|
int state;
|
||||||
|
uint32_t out_bytes;
|
||||||
|
uint32_t in_bytes;
|
||||||
|
uint32_t timeout;
|
||||||
|
SpiceTimer *timer;
|
||||||
|
} RedChannelClientConnectivityMonitor;
|
||||||
|
|
||||||
typedef struct OutgoingHandler {
|
typedef struct OutgoingHandler {
|
||||||
OutgoingHandlerInterface *cb;
|
OutgoingHandlerInterface *cb;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|||||||
@ -93,6 +93,8 @@ typedef struct MarkerPipeItem {
|
|||||||
|
|
||||||
static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t timeout)
|
static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t timeout)
|
||||||
{
|
{
|
||||||
|
SpiceCoreInterfaceInternal *core;
|
||||||
|
|
||||||
if (!rcc->priv->latency_monitor.timer) {
|
if (!rcc->priv->latency_monitor.timer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -100,11 +102,15 @@ static void red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rcc->priv->latency_monitor.state = PING_STATE_TIMER;
|
rcc->priv->latency_monitor.state = PING_STATE_TIMER;
|
||||||
rcc->priv->channel->core->timer_start(rcc->priv->latency_monitor.timer, timeout);
|
|
||||||
|
core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
|
core->timer_start(rcc->priv->latency_monitor.timer, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
|
static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
|
SpiceCoreInterfaceInternal *core;
|
||||||
|
|
||||||
if (!rcc->priv->latency_monitor.timer) {
|
if (!rcc->priv->latency_monitor.timer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -112,7 +118,8 @@ static void red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcc->priv->channel->core->timer_cancel(rcc->priv->latency_monitor.timer);
|
core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
|
core->timer_cancel(rcc->priv->latency_monitor.timer);
|
||||||
rcc->priv->latency_monitor.state = PING_STATE_NONE;
|
rcc->priv->latency_monitor.state = PING_STATE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,10 +194,10 @@ red_channel_client_set_property(GObject *object,
|
|||||||
break;
|
break;
|
||||||
case PROP_CHANNEL:
|
case PROP_CHANNEL:
|
||||||
if (self->priv->channel)
|
if (self->priv->channel)
|
||||||
red_channel_unref(self->priv->channel);
|
g_object_unref(self->priv->channel);
|
||||||
self->priv->channel = g_value_get_pointer(value);
|
self->priv->channel = g_value_get_pointer(value);
|
||||||
if (self->priv->channel)
|
if (self->priv->channel)
|
||||||
red_channel_ref(self->priv->channel);
|
g_object_ref(self->priv->channel);
|
||||||
break;
|
break;
|
||||||
case PROP_CLIENT:
|
case PROP_CLIENT:
|
||||||
self->priv->client = g_value_get_pointer(value);
|
self->priv->client = g_value_get_pointer(value);
|
||||||
@ -243,7 +250,7 @@ red_channel_client_finalize(GObject *object)
|
|||||||
|
|
||||||
red_channel_client_destroy_remote_caps(self);
|
red_channel_client_destroy_remote_caps(self);
|
||||||
if (self->priv->channel) {
|
if (self->priv->channel) {
|
||||||
red_channel_unref(self->priv->channel);
|
g_object_unref(self->priv->channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS(red_channel_client_parent_class)->finalize(object);
|
G_OBJECT_CLASS(red_channel_client_parent_class)->finalize(object);
|
||||||
@ -361,7 +368,6 @@ void red_channel_client_on_output(void *opaque, int n)
|
|||||||
if (rcc->priv->connectivity_monitor.timer) {
|
if (rcc->priv->connectivity_monitor.timer) {
|
||||||
rcc->priv->connectivity_monitor.out_bytes += n;
|
rcc->priv->connectivity_monitor.out_bytes += n;
|
||||||
}
|
}
|
||||||
stat_inc_counter(reds, rcc->priv->channel->out_bytes_counter, n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_client_on_input(void *opaque, int n)
|
void red_channel_client_on_input(void *opaque, int n)
|
||||||
@ -391,12 +397,14 @@ void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
|
|||||||
|
|
||||||
void red_channel_client_on_out_block(void *opaque)
|
void red_channel_client_on_out_block(void *opaque)
|
||||||
{
|
{
|
||||||
|
SpiceCoreInterfaceInternal *core;
|
||||||
RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
|
RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
|
||||||
|
|
||||||
rcc->priv->send_data.blocked = TRUE;
|
rcc->priv->send_data.blocked = TRUE;
|
||||||
rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
|
core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
SPICE_WATCH_EVENT_READ |
|
core->watch_update_mask(rcc->priv->stream->watch,
|
||||||
SPICE_WATCH_EVENT_WRITE);
|
SPICE_WATCH_EVENT_READ |
|
||||||
|
SPICE_WATCH_EVENT_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int red_channel_client_urgent_marshaller_is_active(RedChannelClient *rcc)
|
static inline int red_channel_client_urgent_marshaller_is_active(RedChannelClient *rcc)
|
||||||
@ -439,9 +447,9 @@ static void red_channel_client_send_migrate(RedChannelClient *rcc)
|
|||||||
SpiceMsgMigrate migrate;
|
SpiceMsgMigrate migrate;
|
||||||
|
|
||||||
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
|
red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
|
||||||
migrate.flags = rcc->priv->channel->migration_flags;
|
g_object_get(rcc->priv->channel, "migration-flags", &migrate.flags, NULL);
|
||||||
spice_marshall_msg_migrate(rcc->priv->send_data.marshaller, &migrate);
|
spice_marshall_msg_migrate(rcc->priv->send_data.marshaller, &migrate);
|
||||||
if (rcc->priv->channel->migration_flags & SPICE_MIGRATE_NEED_FLUSH) {
|
if (migrate.flags & SPICE_MIGRATE_NEED_FLUSH) {
|
||||||
rcc->priv->wait_migrate_flush_mark = TRUE;
|
rcc->priv->wait_migrate_flush_mark = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +523,7 @@ static void red_channel_client_send_item(RedChannelClient *rcc, RedPipeItem *ite
|
|||||||
case RED_PIPE_ITEM_TYPE_MARKER:
|
case RED_PIPE_ITEM_TYPE_MARKER:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rcc->priv->channel->channel_cbs.send_item(rcc, item);
|
red_channel_send_item(rcc->priv->channel, rcc, item);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
red_pipe_item_unref(item);
|
red_pipe_item_unref(item);
|
||||||
@ -558,9 +566,10 @@ void red_channel_client_on_out_msg_done(void *opaque)
|
|||||||
|
|
||||||
red_channel_client_release_sent_item(rcc);
|
red_channel_client_release_sent_item(rcc);
|
||||||
if (rcc->priv->send_data.blocked) {
|
if (rcc->priv->send_data.blocked) {
|
||||||
|
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
rcc->priv->send_data.blocked = FALSE;
|
rcc->priv->send_data.blocked = FALSE;
|
||||||
rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
|
core->watch_update_mask(rcc->priv->stream->watch,
|
||||||
SPICE_WATCH_EVENT_READ);
|
SPICE_WATCH_EVENT_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (red_channel_client_urgent_marshaller_is_active(rcc)) {
|
if (red_channel_client_urgent_marshaller_is_active(rcc)) {
|
||||||
@ -645,8 +654,13 @@ static void red_channel_client_ping_timer(void *opaque)
|
|||||||
|
|
||||||
static inline int red_channel_client_waiting_for_ack(RedChannelClient *rcc)
|
static inline int red_channel_client_waiting_for_ack(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
return (rcc->priv->channel->handle_acks &&
|
gboolean handle_acks;
|
||||||
(rcc->priv->ack_data.messages_window > rcc->priv->ack_data.client_window * 2));
|
g_object_get(rcc->priv->channel,
|
||||||
|
"handle-acks", &handle_acks,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return (handle_acks && (rcc->priv->ack_data.messages_window >
|
||||||
|
rcc->priv->ack_data.client_window * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -687,6 +701,7 @@ static void red_channel_client_connectivity_timer(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_alive) {
|
if (is_alive) {
|
||||||
|
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
monitor->in_bytes = 0;
|
monitor->in_bytes = 0;
|
||||||
monitor->out_bytes = 0;
|
monitor->out_bytes = 0;
|
||||||
if (rcc->priv->send_data.blocked || red_channel_client_waiting_for_ack(rcc)) {
|
if (rcc->priv->send_data.blocked || red_channel_client_waiting_for_ack(rcc)) {
|
||||||
@ -697,18 +712,24 @@ static void red_channel_client_connectivity_timer(void *opaque)
|
|||||||
} else {
|
} else {
|
||||||
monitor->state = CONNECTIVITY_STATE_CONNECTED;
|
monitor->state = CONNECTIVITY_STATE_CONNECTED;
|
||||||
}
|
}
|
||||||
rcc->priv->channel->core->timer_start(rcc->priv->connectivity_monitor.timer,
|
core->timer_start(rcc->priv->connectivity_monitor.timer,
|
||||||
rcc->priv->connectivity_monitor.timeout);
|
rcc->priv->connectivity_monitor.timeout);
|
||||||
} else {
|
} else {
|
||||||
|
uint32_t type, id;
|
||||||
|
g_object_get(rcc->priv->channel,
|
||||||
|
"channel-type", &type,
|
||||||
|
"id", &id,
|
||||||
|
NULL);
|
||||||
monitor->state = CONNECTIVITY_STATE_DISCONNECTED;
|
monitor->state = CONNECTIVITY_STATE_DISCONNECTED;
|
||||||
spice_warning("rcc %p on channel %d:%d has been unresponsive for more than %u ms, disconnecting",
|
spice_warning("rcc %p on channel %d:%d has been unresponsive for more than %u ms, disconnecting",
|
||||||
rcc, rcc->priv->channel->type, rcc->priv->channel->id, monitor->timeout);
|
rcc, type, id, monitor->timeout);
|
||||||
red_channel_client_disconnect(rcc);
|
red_channel_client_disconnect(rcc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uint32_t timeout_ms)
|
void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uint32_t timeout_ms)
|
||||||
{
|
{
|
||||||
|
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
if (!red_channel_client_is_connected(rcc)) {
|
if (!red_channel_client_is_connected(rcc)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -721,8 +742,8 @@ void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uin
|
|||||||
* on this channel.
|
* on this channel.
|
||||||
*/
|
*/
|
||||||
if (rcc->priv->latency_monitor.timer == NULL) {
|
if (rcc->priv->latency_monitor.timer == NULL) {
|
||||||
rcc->priv->latency_monitor.timer = rcc->priv->channel->core->timer_add(
|
rcc->priv->latency_monitor.timer = core->timer_add(
|
||||||
rcc->priv->channel->core, red_channel_client_ping_timer, rcc);
|
core, red_channel_client_ping_timer, rcc);
|
||||||
if (!red_client_during_migrate_at_target(rcc->priv->client)) {
|
if (!red_client_during_migrate_at_target(rcc->priv->client)) {
|
||||||
red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
|
red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
@ -730,12 +751,12 @@ void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uin
|
|||||||
}
|
}
|
||||||
if (rcc->priv->connectivity_monitor.timer == NULL) {
|
if (rcc->priv->connectivity_monitor.timer == NULL) {
|
||||||
rcc->priv->connectivity_monitor.state = CONNECTIVITY_STATE_CONNECTED;
|
rcc->priv->connectivity_monitor.state = CONNECTIVITY_STATE_CONNECTED;
|
||||||
rcc->priv->connectivity_monitor.timer = rcc->priv->channel->core->timer_add(
|
rcc->priv->connectivity_monitor.timer = core->timer_add(
|
||||||
rcc->priv->channel->core, red_channel_client_connectivity_timer, rcc);
|
core, red_channel_client_connectivity_timer, rcc);
|
||||||
rcc->priv->connectivity_monitor.timeout = timeout_ms;
|
rcc->priv->connectivity_monitor.timeout = timeout_ms;
|
||||||
if (!red_client_during_migrate_at_target(rcc->priv->client)) {
|
if (!red_client_during_migrate_at_target(rcc->priv->client)) {
|
||||||
rcc->priv->channel->core->timer_start(rcc->priv->connectivity_monitor.timer,
|
core->timer_start(rcc->priv->connectivity_monitor.timer,
|
||||||
rcc->priv->connectivity_monitor.timeout);
|
rcc->priv->connectivity_monitor.timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -832,9 +853,11 @@ static const SpiceDataHeaderOpaque mini_header_wrapper = {NULL, sizeof(SpiceMini
|
|||||||
|
|
||||||
static int red_channel_client_pre_create_validate(RedChannel *channel, RedClient *client)
|
static int red_channel_client_pre_create_validate(RedChannel *channel, RedClient *client)
|
||||||
{
|
{
|
||||||
if (red_client_get_channel(client, channel->type, channel->id)) {
|
uint32_t type, id;
|
||||||
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
|
if (red_client_get_channel(client, type, id)) {
|
||||||
spice_printerr("Error client %p: duplicate channel type %d id %d",
|
spice_printerr("Error client %p: duplicate channel type %d id %d",
|
||||||
client, channel->type, channel->id);
|
client, type, id);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -845,24 +868,28 @@ static gboolean red_channel_client_initable_init(GInitable *initable,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GError *local_error = NULL;
|
GError *local_error = NULL;
|
||||||
|
SpiceCoreInterfaceInternal *core;
|
||||||
RedChannelClient *self = RED_CHANNEL_CLIENT(initable);
|
RedChannelClient *self = RED_CHANNEL_CLIENT(initable);
|
||||||
pthread_mutex_lock(&self->priv->client->lock);
|
pthread_mutex_lock(&self->priv->client->lock);
|
||||||
if (!red_channel_client_pre_create_validate(self->priv->channel, self->priv->client)) {
|
if (!red_channel_client_pre_create_validate(self->priv->channel, self->priv->client)) {
|
||||||
|
uint32_t id, type;
|
||||||
|
g_object_get(self->priv->channel,
|
||||||
|
"channel-type", &type,
|
||||||
|
"id", &id,
|
||||||
|
NULL);
|
||||||
g_set_error(&local_error,
|
g_set_error(&local_error,
|
||||||
SPICE_SERVER_ERROR,
|
SPICE_SERVER_ERROR,
|
||||||
SPICE_SERVER_ERROR_FAILED,
|
SPICE_SERVER_ERROR_FAILED,
|
||||||
"Client %p: duplicate channel type %d id %d",
|
"Client %p: duplicate channel type %d id %d",
|
||||||
self->priv->client, self->priv->channel->type,
|
self->priv->client, type, id);
|
||||||
self->priv->channel->id);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core = red_channel_get_core_interface(self->priv->channel);
|
||||||
if (self->priv->monitor_latency
|
if (self->priv->monitor_latency
|
||||||
&& reds_stream_get_family(self->priv->stream) != AF_UNIX) {
|
&& reds_stream_get_family(self->priv->stream) != AF_UNIX) {
|
||||||
self->priv->latency_monitor.timer =
|
self->priv->latency_monitor.timer =
|
||||||
self->priv->channel->core->timer_add(self->priv->channel->core,
|
core->timer_add(core, red_channel_client_ping_timer, self);
|
||||||
red_channel_client_ping_timer,
|
|
||||||
self);
|
|
||||||
|
|
||||||
if (!self->priv->client->during_target_migrate) {
|
if (!self->priv->client->during_target_migrate) {
|
||||||
red_channel_client_start_ping_timer(self,
|
red_channel_client_start_ping_timer(self,
|
||||||
@ -872,27 +899,26 @@ static gboolean red_channel_client_initable_init(GInitable *initable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
self->incoming.opaque = self;
|
self->incoming.opaque = self;
|
||||||
self->incoming.cb = &self->priv->channel->incoming_cb;
|
self->incoming.cb = red_channel_get_incoming_handler(self->priv->channel);
|
||||||
self->incoming.header.data = self->incoming.header_buf;
|
self->incoming.header.data = self->incoming.header_buf;
|
||||||
|
|
||||||
self->priv->outgoing.opaque = self;
|
self->priv->outgoing.opaque = self;
|
||||||
self->priv->outgoing.cb = &self->priv->channel->outgoing_cb;
|
self->priv->outgoing.cb = red_channel_get_outgoing_handler(self->priv->channel);
|
||||||
self->priv->outgoing.pos = 0;
|
self->priv->outgoing.pos = 0;
|
||||||
self->priv->outgoing.size = 0;
|
self->priv->outgoing.size = 0;
|
||||||
|
|
||||||
g_queue_init(&self->priv->pipe);
|
g_queue_init(&self->priv->pipe);
|
||||||
if (self->priv->stream)
|
if (self->priv->stream)
|
||||||
self->priv->stream->watch =
|
self->priv->stream->watch =
|
||||||
self->priv->channel->core->watch_add(self->priv->channel->core,
|
core->watch_add(core, self->priv->stream->socket,
|
||||||
self->priv->stream->socket,
|
SPICE_WATCH_EVENT_READ,
|
||||||
SPICE_WATCH_EVENT_READ,
|
red_channel_client_event,
|
||||||
red_channel_client_event,
|
self);
|
||||||
self);
|
self->priv->id = red_channel_get_n_clients(self->priv->channel);
|
||||||
self->priv->id = g_list_length(self->priv->channel->clients);
|
|
||||||
red_channel_add_client(self->priv->channel, self);
|
red_channel_add_client(self->priv->channel, self);
|
||||||
red_client_add_channel(self->priv->client, self);
|
red_client_add_channel(self->priv->client, self);
|
||||||
|
|
||||||
if (!self->priv->channel->channel_cbs.config_socket(self)) {
|
if (!red_channel_config_socket(self->priv->channel, self)) {
|
||||||
g_set_error_literal(&local_error,
|
g_set_error_literal(&local_error,
|
||||||
SPICE_SERVER_ERROR,
|
SPICE_SERVER_ERROR,
|
||||||
SPICE_SERVER_ERROR_FAILED,
|
SPICE_SERVER_ERROR_FAILED,
|
||||||
@ -953,8 +979,9 @@ static void red_channel_client_seamless_migration_done(RedChannelClient *rcc)
|
|||||||
red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
|
red_channel_client_start_ping_timer(rcc, PING_TEST_IDLE_NET_TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
if (rcc->priv->connectivity_monitor.timer) {
|
if (rcc->priv->connectivity_monitor.timer) {
|
||||||
rcc->priv->channel->core->timer_start(rcc->priv->connectivity_monitor.timer,
|
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
rcc->priv->connectivity_monitor.timeout);
|
core->timer_start(rcc->priv->connectivity_monitor.timer,
|
||||||
|
rcc->priv->connectivity_monitor.timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -973,13 +1000,14 @@ int red_channel_client_is_waiting_for_migrate_data(RedChannelClient *rcc)
|
|||||||
|
|
||||||
void red_channel_client_default_migrate(RedChannelClient *rcc)
|
void red_channel_client_default_migrate(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
|
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
if (rcc->priv->latency_monitor.timer) {
|
if (rcc->priv->latency_monitor.timer) {
|
||||||
red_channel_client_cancel_ping_timer(rcc);
|
red_channel_client_cancel_ping_timer(rcc);
|
||||||
rcc->priv->channel->core->timer_remove(rcc->priv->latency_monitor.timer);
|
core->timer_remove(rcc->priv->latency_monitor.timer);
|
||||||
rcc->priv->latency_monitor.timer = NULL;
|
rcc->priv->latency_monitor.timer = NULL;
|
||||||
}
|
}
|
||||||
if (rcc->priv->connectivity_monitor.timer) {
|
if (rcc->priv->connectivity_monitor.timer) {
|
||||||
rcc->priv->channel->core->timer_remove(rcc->priv->connectivity_monitor.timer);
|
core->timer_remove(rcc->priv->connectivity_monitor.timer);
|
||||||
rcc->priv->connectivity_monitor.timer = NULL;
|
rcc->priv->connectivity_monitor.timer = NULL;
|
||||||
}
|
}
|
||||||
red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_MIGRATE);
|
red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_MIGRATE);
|
||||||
@ -996,7 +1024,8 @@ void red_channel_client_destroy(RedChannelClient *rcc)
|
|||||||
void red_channel_client_shutdown(RedChannelClient *rcc)
|
void red_channel_client_shutdown(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
if (rcc->priv->stream && !rcc->priv->stream->shutdown) {
|
if (rcc->priv->stream && !rcc->priv->stream->shutdown) {
|
||||||
rcc->priv->channel->core->watch_remove(rcc->priv->stream->watch);
|
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
|
core->watch_remove(rcc->priv->stream->watch);
|
||||||
rcc->priv->stream->watch = NULL;
|
rcc->priv->stream->watch = NULL;
|
||||||
shutdown(rcc->priv->stream->socket, SHUT_RDWR);
|
shutdown(rcc->priv->stream->socket, SHUT_RDWR);
|
||||||
rcc->priv->stream->shutdown = TRUE;
|
rcc->priv->stream->shutdown = TRUE;
|
||||||
@ -1227,8 +1256,10 @@ void red_channel_client_push(RedChannelClient *rcc)
|
|||||||
}
|
}
|
||||||
if (red_channel_client_no_item_being_sent(rcc) && g_queue_is_empty(&rcc->priv->pipe)
|
if (red_channel_client_no_item_being_sent(rcc) && g_queue_is_empty(&rcc->priv->pipe)
|
||||||
&& rcc->priv->stream->watch) {
|
&& rcc->priv->stream->watch) {
|
||||||
rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
|
SpiceCoreInterfaceInternal *core;
|
||||||
SPICE_WATCH_EVENT_READ);
|
core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
|
core->watch_update_mask(rcc->priv->stream->watch,
|
||||||
|
SPICE_WATCH_EVENT_READ);
|
||||||
}
|
}
|
||||||
rcc->priv->during_send = FALSE;
|
rcc->priv->during_send = FALSE;
|
||||||
g_object_unref(rcc);
|
g_object_unref(rcc);
|
||||||
@ -1302,8 +1333,9 @@ static void red_channel_client_handle_pong(RedChannelClient *rcc, SpiceMsgPing *
|
|||||||
static void red_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc)
|
static void red_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
if (channel->channel_cbs.handle_migrate_flush_mark) {
|
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
|
||||||
channel->channel_cbs.handle_migrate_flush_mark(rcc);
|
if (klass->handle_migrate_flush_mark) {
|
||||||
|
klass->handle_migrate_flush_mark(rcc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,20 +1351,24 @@ static void red_channel_client_handle_migrate_data(RedChannelClient *rcc,
|
|||||||
void *message)
|
void *message)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
|
||||||
|
uint32_t type, id;
|
||||||
|
|
||||||
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
spice_debug("channel type %d id %d rcc %p size %u",
|
spice_debug("channel type %d id %d rcc %p size %u",
|
||||||
channel->type, channel->id, rcc, size);
|
type, id, rcc, size);
|
||||||
if (!channel->channel_cbs.handle_migrate_data) {
|
if (!klass->handle_migrate_data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!red_channel_client_is_waiting_for_migrate_data(rcc)) {
|
if (!red_channel_client_is_waiting_for_migrate_data(rcc)) {
|
||||||
spice_channel_client_error(rcc, "unexpected");
|
spice_channel_client_error(rcc, "unexpected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (channel->channel_cbs.handle_migrate_data_get_serial) {
|
if (klass->handle_migrate_data_get_serial) {
|
||||||
red_channel_client_set_message_serial(rcc,
|
red_channel_client_set_message_serial(rcc,
|
||||||
channel->channel_cbs.handle_migrate_data_get_serial(rcc, size, message));
|
klass->handle_migrate_data_get_serial(rcc, size, message));
|
||||||
}
|
}
|
||||||
if (!channel->channel_cbs.handle_migrate_data(rcc, size, message)) {
|
if (!klass->handle_migrate_data(rcc, size, message)) {
|
||||||
spice_channel_client_error(rcc, "handle_migrate_data failed");
|
spice_channel_client_error(rcc, "handle_migrate_data failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1448,9 +1484,10 @@ static inline gboolean prepare_pipe_add(RedChannelClient *rcc, RedPipeItem *item
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (g_queue_is_empty(&rcc->priv->pipe) && rcc->priv->stream->watch) {
|
if (g_queue_is_empty(&rcc->priv->pipe) && rcc->priv->stream->watch) {
|
||||||
rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
|
SpiceCoreInterfaceInternal *core;
|
||||||
SPICE_WATCH_EVENT_READ |
|
core = red_channel_get_core_interface(rcc->priv->channel);
|
||||||
SPICE_WATCH_EVENT_WRITE);
|
core->watch_update_mask(rcc->priv->stream->watch,
|
||||||
|
SPICE_WATCH_EVENT_READ | SPICE_WATCH_EVENT_WRITE);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -1562,7 +1599,7 @@ gboolean red_channel_client_is_mini_header(RedChannelClient *rcc)
|
|||||||
static gboolean red_channel_client_default_is_connected(RedChannelClient *rcc)
|
static gboolean red_channel_client_default_is_connected(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
return rcc->priv->channel
|
return rcc->priv->channel
|
||||||
&& (g_list_find(rcc->priv->channel->clients, rcc) != NULL);
|
&& (g_list_find(red_channel_get_clients(rcc->priv->channel), rcc) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean red_channel_client_is_connected(RedChannelClient *rcc)
|
gboolean red_channel_client_is_connected(RedChannelClient *rcc)
|
||||||
@ -1613,27 +1650,30 @@ void red_channel_client_push_set_ack(RedChannelClient *rcc)
|
|||||||
static void red_channel_client_default_disconnect(RedChannelClient *rcc)
|
static void red_channel_client_default_disconnect(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
RedChannel *channel = rcc->priv->channel;
|
RedChannel *channel = rcc->priv->channel;
|
||||||
|
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(channel);
|
||||||
|
uint32_t type, id;
|
||||||
|
|
||||||
if (!red_channel_client_is_connected(rcc)) {
|
if (!red_channel_client_is_connected(rcc)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
|
spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc, channel,
|
||||||
channel->type, channel->id);
|
type, id);
|
||||||
red_channel_client_pipe_clear(rcc);
|
red_channel_client_pipe_clear(rcc);
|
||||||
if (rcc->priv->stream->watch) {
|
if (rcc->priv->stream->watch) {
|
||||||
channel->core->watch_remove(rcc->priv->stream->watch);
|
core->watch_remove(rcc->priv->stream->watch);
|
||||||
rcc->priv->stream->watch = NULL;
|
rcc->priv->stream->watch = NULL;
|
||||||
}
|
}
|
||||||
if (rcc->priv->latency_monitor.timer) {
|
if (rcc->priv->latency_monitor.timer) {
|
||||||
channel->core->timer_remove(rcc->priv->latency_monitor.timer);
|
core->timer_remove(rcc->priv->latency_monitor.timer);
|
||||||
rcc->priv->latency_monitor.timer = NULL;
|
rcc->priv->latency_monitor.timer = NULL;
|
||||||
}
|
}
|
||||||
if (rcc->priv->connectivity_monitor.timer) {
|
if (rcc->priv->connectivity_monitor.timer) {
|
||||||
channel->core->timer_remove(rcc->priv->connectivity_monitor.timer);
|
core->timer_remove(rcc->priv->connectivity_monitor.timer);
|
||||||
rcc->priv->connectivity_monitor.timer = NULL;
|
rcc->priv->connectivity_monitor.timer = NULL;
|
||||||
}
|
}
|
||||||
red_channel_remove_client(channel, rcc);
|
red_channel_remove_client(channel, rcc);
|
||||||
channel->channel_cbs.on_disconnect(rcc);
|
red_channel_on_disconnect(channel, rcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_client_disconnect(RedChannelClient *rcc)
|
void red_channel_client_disconnect(RedChannelClient *rcc)
|
||||||
@ -1800,13 +1840,18 @@ void red_channel_client_pipe_remove_and_release_pos(RedChannelClient *rcc,
|
|||||||
gboolean red_channel_client_set_migration_seamless(RedChannelClient *rcc)
|
gboolean red_channel_client_set_migration_seamless(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
uint32_t type, id, flags;
|
||||||
|
|
||||||
if (rcc->priv->channel->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
|
g_object_get(rcc->priv->channel,
|
||||||
|
"channel-type", &type,
|
||||||
|
"id", &id,
|
||||||
|
"migration-flags", &flags,
|
||||||
|
NULL);
|
||||||
|
if (flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
|
||||||
rcc->priv->wait_migrate_data = TRUE;
|
rcc->priv->wait_migrate_data = TRUE;
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
spice_debug("channel type %d id %d rcc %p wait data %d", rcc->priv->channel->type,
|
spice_debug("channel type %d id %d rcc %p wait data %d", type, id, rcc,
|
||||||
rcc->priv->channel->id, rcc,
|
|
||||||
rcc->priv->wait_migrate_data);
|
rcc->priv->wait_migrate_data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@ -62,8 +62,10 @@ GType red_channel_client_get_type(void) G_GNUC_CONST;
|
|||||||
#define spice_channel_client_error(rcc, format, ...) \
|
#define spice_channel_client_error(rcc, format, ...) \
|
||||||
do { \
|
do { \
|
||||||
RedChannel *_ch = red_channel_client_get_channel(rcc); \
|
RedChannel *_ch = red_channel_client_get_channel(rcc); \
|
||||||
|
uint32_t _type, _id; \
|
||||||
|
g_object_get(_ch, "channel-type", &_type, "id", &_id, NULL); \
|
||||||
spice_warning("rcc %p type %u id %u: " format, rcc, \
|
spice_warning("rcc %p type %u id %u: " format, rcc, \
|
||||||
_ch->type, _ch->id, ## __VA_ARGS__); \
|
type, id, ## __VA_ARGS__); \
|
||||||
red_channel_client_shutdown(rcc); \
|
red_channel_client_shutdown(rcc); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|||||||
@ -69,9 +69,137 @@
|
|||||||
* from the channel's thread.
|
* from the channel's thread.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void red_channel_receive(RedChannel *channel)
|
G_DEFINE_ABSTRACT_TYPE(RedChannel, red_channel, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
#define CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), RED_TYPE_CHANNEL, RedChannelPrivate))
|
||||||
|
|
||||||
|
struct RedChannelPrivate
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, (GFunc)red_channel_client_receive, NULL);
|
uint32_t type;
|
||||||
|
uint32_t id;
|
||||||
|
|
||||||
|
SpiceCoreInterfaceInternal *core;
|
||||||
|
gboolean handle_acks;
|
||||||
|
|
||||||
|
// RedChannel will hold only connected channel clients
|
||||||
|
// (logic - when pushing pipe item to all channel clients, there
|
||||||
|
// is no need to go over disconnect clients)
|
||||||
|
// . While client will hold the channel clients till it is destroyed
|
||||||
|
// and then it will destroy them as well.
|
||||||
|
// However RCC still holds a reference to the Channel.
|
||||||
|
// Maybe replace these logic with ref count?
|
||||||
|
// TODO: rename to 'connected_clients'?
|
||||||
|
GList *clients;
|
||||||
|
|
||||||
|
RedChannelCapabilities local_caps;
|
||||||
|
uint32_t migration_flags;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
OutgoingHandlerInterface outgoing_cb;
|
||||||
|
IncomingHandlerInterface incoming_cb;
|
||||||
|
|
||||||
|
ClientCbs client_cbs;
|
||||||
|
// TODO: when different channel_clients are in different threads
|
||||||
|
// from Channel -> need to protect!
|
||||||
|
pthread_t thread_id;
|
||||||
|
RedsState *reds;
|
||||||
|
#ifdef RED_STATISTICS
|
||||||
|
StatNodeRef stat;
|
||||||
|
uint64_t *out_bytes_counter;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP0,
|
||||||
|
PROP_SPICE_SERVER,
|
||||||
|
PROP_CORE_INTERFACE,
|
||||||
|
PROP_TYPE,
|
||||||
|
PROP_ID,
|
||||||
|
PROP_HANDLE_ACKS,
|
||||||
|
PROP_MIGRATION_FLAGS
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_channel_get_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
RedChannel *self = RED_CHANNEL(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_SPICE_SERVER:
|
||||||
|
g_value_set_pointer(value, self->priv->reds);
|
||||||
|
break;
|
||||||
|
case PROP_CORE_INTERFACE:
|
||||||
|
g_value_set_pointer(value, self->priv->core);
|
||||||
|
break;
|
||||||
|
case PROP_TYPE:
|
||||||
|
g_value_set_int(value, self->priv->type);
|
||||||
|
break;
|
||||||
|
case PROP_ID:
|
||||||
|
g_value_set_uint(value, self->priv->id);
|
||||||
|
break;
|
||||||
|
case PROP_HANDLE_ACKS:
|
||||||
|
g_value_set_boolean(value, self->priv->handle_acks);
|
||||||
|
break;
|
||||||
|
case PROP_MIGRATION_FLAGS:
|
||||||
|
g_value_set_uint(value, self->priv->migration_flags);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_channel_set_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
RedChannel *self = RED_CHANNEL(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_SPICE_SERVER:
|
||||||
|
self->priv->reds = g_value_get_pointer(value);
|
||||||
|
break;
|
||||||
|
case PROP_CORE_INTERFACE:
|
||||||
|
self->priv->core = g_value_get_pointer(value);
|
||||||
|
break;
|
||||||
|
case PROP_TYPE:
|
||||||
|
self->priv->type = g_value_get_int(value);
|
||||||
|
break;
|
||||||
|
case PROP_ID:
|
||||||
|
self->priv->id = g_value_get_uint(value);
|
||||||
|
break;
|
||||||
|
case PROP_HANDLE_ACKS:
|
||||||
|
self->priv->handle_acks = g_value_get_boolean(value);
|
||||||
|
break;
|
||||||
|
case PROP_MIGRATION_FLAGS:
|
||||||
|
self->priv->migration_flags = g_value_get_uint(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_channel_finalize(GObject *object)
|
||||||
|
{
|
||||||
|
RedChannel *self = RED_CHANNEL(object);
|
||||||
|
|
||||||
|
if (self->priv->local_caps.num_common_caps) {
|
||||||
|
free(self->priv->local_caps.common_caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->priv->local_caps.num_caps) {
|
||||||
|
free(self->priv->local_caps.caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(red_channel_parent_class)->finalize(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
|
static void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
|
||||||
@ -79,10 +207,164 @@ static void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
|
|||||||
red_channel_client_disconnect(rcc);
|
red_channel_client_disconnect(rcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void red_channel_on_output(void *opaque, int n)
|
||||||
|
{
|
||||||
|
RedChannelClient *rcc = opaque;
|
||||||
|
RedChannel *self = red_channel_client_get_channel(rcc);
|
||||||
|
|
||||||
|
red_channel_client_on_output(opaque, n);
|
||||||
|
|
||||||
|
stat_inc_counter(self->priv->reds, self->priv->out_bytes_counter, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_channel_constructed(GObject *object)
|
||||||
|
{
|
||||||
|
RedChannel *self = RED_CHANNEL(object);
|
||||||
|
spice_debug("%p: channel type %d id %d thread_id 0x%lx", self,
|
||||||
|
self->priv->type, self->priv->id, self->priv->thread_id);
|
||||||
|
|
||||||
|
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
|
||||||
|
|
||||||
|
spice_assert(klass->config_socket && klass->on_disconnect &&
|
||||||
|
klass->alloc_recv_buf && klass->release_recv_buf);
|
||||||
|
spice_assert(klass->handle_migrate_data ||
|
||||||
|
!(self->priv->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER));
|
||||||
|
|
||||||
|
self->priv->incoming_cb.alloc_msg_buf =
|
||||||
|
(alloc_msg_recv_buf_proc)klass->alloc_recv_buf;
|
||||||
|
self->priv->incoming_cb.release_msg_buf =
|
||||||
|
(release_msg_recv_buf_proc)klass->release_recv_buf;
|
||||||
|
self->priv->incoming_cb.handle_message = (handle_message_proc)klass->handle_message;
|
||||||
|
self->priv->incoming_cb.handle_parsed = (handle_parsed_proc)klass->handle_parsed;
|
||||||
|
self->priv->incoming_cb.parser = klass->parser;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(red_channel_parent_class)->constructed(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void red_channel_client_default_connect(RedChannel *channel, RedClient *client,
|
||||||
|
RedsStream *stream,
|
||||||
|
int migration,
|
||||||
|
int num_common_caps, uint32_t *common_caps,
|
||||||
|
int num_caps, uint32_t *caps)
|
||||||
|
{
|
||||||
|
spice_error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void red_channel_client_default_disconnect(RedChannelClient *base)
|
||||||
|
{
|
||||||
|
red_channel_client_disconnect(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_channel_class_init(RedChannelClass *klass)
|
||||||
|
{
|
||||||
|
GParamSpec *spec;
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
g_type_class_add_private(klass, sizeof (RedChannelPrivate));
|
||||||
|
|
||||||
|
object_class->get_property = red_channel_get_property;
|
||||||
|
object_class->set_property = red_channel_set_property;
|
||||||
|
object_class->finalize = red_channel_finalize;
|
||||||
|
object_class->constructed = red_channel_constructed;
|
||||||
|
|
||||||
|
spec = g_param_spec_pointer("spice-server",
|
||||||
|
"spice-server",
|
||||||
|
"The spice server associated with this channel",
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
g_object_class_install_property(object_class, PROP_SPICE_SERVER, spec);
|
||||||
|
|
||||||
|
spec = g_param_spec_pointer("core-interface",
|
||||||
|
"core-interface",
|
||||||
|
"The SpiceCoreInterface server associated with this channel",
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
g_object_class_install_property(object_class, PROP_CORE_INTERFACE, spec);
|
||||||
|
|
||||||
|
/* FIXME: generate enums for this in spice-common? */
|
||||||
|
spec = g_param_spec_int("channel-type",
|
||||||
|
"channel type",
|
||||||
|
"Type of this channel",
|
||||||
|
0,
|
||||||
|
SPICE_END_CHANNEL,
|
||||||
|
0,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
g_object_class_install_property(object_class, PROP_TYPE, spec);
|
||||||
|
|
||||||
|
spec = g_param_spec_uint("id",
|
||||||
|
"id",
|
||||||
|
"ID of this channel",
|
||||||
|
0,
|
||||||
|
G_MAXUINT,
|
||||||
|
0,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
g_object_class_install_property(object_class, PROP_ID, spec);
|
||||||
|
|
||||||
|
spec = g_param_spec_boolean("handle-acks",
|
||||||
|
"Handle ACKs",
|
||||||
|
"Whether this channel handles ACKs",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
g_object_class_install_property(object_class, PROP_HANDLE_ACKS, spec);
|
||||||
|
|
||||||
|
spec = g_param_spec_uint("migration-flags",
|
||||||
|
"migration flags",
|
||||||
|
"Migration flags for this channel",
|
||||||
|
0,
|
||||||
|
G_MAXUINT,
|
||||||
|
0,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
g_object_class_install_property(object_class, PROP_MIGRATION_FLAGS, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_channel_init(RedChannel *self)
|
||||||
|
{
|
||||||
|
self->priv = CHANNEL_PRIVATE(self);
|
||||||
|
|
||||||
|
red_channel_set_common_cap(self, SPICE_COMMON_CAP_MINI_HEADER);
|
||||||
|
self->priv->thread_id = pthread_self();
|
||||||
|
self->priv->out_bytes_counter = 0;
|
||||||
|
|
||||||
|
// TODO: send incoming_cb as parameters instead of duplicating?
|
||||||
|
self->priv->incoming_cb.on_error =
|
||||||
|
(on_incoming_error_proc)red_channel_client_default_peer_on_error;
|
||||||
|
self->priv->incoming_cb.on_input = red_channel_client_on_input;
|
||||||
|
self->priv->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size;
|
||||||
|
self->priv->outgoing_cb.prepare = red_channel_client_prepare_out_msg;
|
||||||
|
self->priv->outgoing_cb.on_block = red_channel_client_on_out_block;
|
||||||
|
self->priv->outgoing_cb.on_error =
|
||||||
|
(on_outgoing_error_proc)red_channel_client_default_peer_on_error;
|
||||||
|
self->priv->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done;
|
||||||
|
self->priv->outgoing_cb.on_output = red_channel_on_output;
|
||||||
|
|
||||||
|
self->priv->client_cbs.connect = red_channel_client_default_connect;
|
||||||
|
self->priv->client_cbs.disconnect = red_channel_client_default_disconnect;
|
||||||
|
self->priv->client_cbs.migrate = red_channel_client_default_migrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void red_channel_receive(RedChannel *channel)
|
||||||
|
{
|
||||||
|
g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_receive, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
|
void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
spice_assert(rcc);
|
spice_assert(rcc);
|
||||||
channel->clients = g_list_prepend(channel->clients, rcc);
|
channel->priv->clients = g_list_prepend(channel->priv->clients, rcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int red_channel_test_remote_common_cap(RedChannel *channel, uint32_t cap)
|
int red_channel_test_remote_common_cap(RedChannel *channel, uint32_t cap)
|
||||||
@ -137,7 +419,7 @@ gboolean red_client_seamless_migration_done_for_channel(RedClient *client)
|
|||||||
int red_channel_is_waiting_for_migrate_data(RedChannel *channel)
|
int red_channel_is_waiting_for_migrate_data(RedChannel *channel)
|
||||||
{
|
{
|
||||||
RedChannelClient *rcc;
|
RedChannelClient *rcc;
|
||||||
guint n_clients = g_list_length(channel->clients);
|
guint n_clients = g_list_length(channel->priv->clients);
|
||||||
|
|
||||||
if (!red_channel_is_connected(channel)) {
|
if (!red_channel_is_connected(channel)) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -147,186 +429,44 @@ int red_channel_is_waiting_for_migrate_data(RedChannel *channel)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
spice_assert(n_clients == 1);
|
spice_assert(n_clients == 1);
|
||||||
rcc = g_list_nth_data(channel->clients, 0);
|
rcc = g_list_nth_data(channel->priv->clients, 0);
|
||||||
return red_channel_client_is_waiting_for_migrate_data(rcc);
|
return red_channel_client_is_waiting_for_migrate_data(rcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void red_channel_client_default_connect(RedChannel *channel, RedClient *client,
|
|
||||||
RedsStream *stream,
|
|
||||||
int migration,
|
|
||||||
int num_common_caps, uint32_t *common_caps,
|
|
||||||
int num_caps, uint32_t *caps)
|
|
||||||
{
|
|
||||||
spice_error("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void red_channel_client_default_disconnect(RedChannelClient *base)
|
|
||||||
{
|
|
||||||
red_channel_client_disconnect(base);
|
|
||||||
}
|
|
||||||
|
|
||||||
RedChannel *red_channel_create(int size,
|
|
||||||
RedsState *reds,
|
|
||||||
const SpiceCoreInterfaceInternal *core,
|
|
||||||
uint32_t type, uint32_t id,
|
|
||||||
int handle_acks,
|
|
||||||
channel_handle_message_proc handle_message,
|
|
||||||
const ChannelCbs *channel_cbs,
|
|
||||||
uint32_t migration_flags)
|
|
||||||
{
|
|
||||||
RedChannel *channel;
|
|
||||||
ClientCbs client_cbs = { NULL, };
|
|
||||||
|
|
||||||
spice_assert(size >= sizeof(*channel));
|
|
||||||
spice_assert(channel_cbs->config_socket && channel_cbs->on_disconnect && handle_message &&
|
|
||||||
channel_cbs->alloc_recv_buf);
|
|
||||||
spice_assert(channel_cbs->handle_migrate_data ||
|
|
||||||
!(migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER));
|
|
||||||
channel = spice_malloc0(size);
|
|
||||||
channel->type = type;
|
|
||||||
channel->id = id;
|
|
||||||
channel->refs = 1;
|
|
||||||
channel->handle_acks = handle_acks;
|
|
||||||
channel->migration_flags = migration_flags;
|
|
||||||
channel->channel_cbs = *channel_cbs;
|
|
||||||
|
|
||||||
channel->reds = reds;
|
|
||||||
channel->core = core;
|
|
||||||
|
|
||||||
// TODO: send incoming_cb as parameters instead of duplicating?
|
|
||||||
channel->incoming_cb.alloc_msg_buf = (alloc_msg_recv_buf_proc)channel_cbs->alloc_recv_buf;
|
|
||||||
channel->incoming_cb.release_msg_buf = (release_msg_recv_buf_proc)channel_cbs->release_recv_buf;
|
|
||||||
channel->incoming_cb.handle_message = (handle_message_proc)handle_message;
|
|
||||||
channel->incoming_cb.on_error =
|
|
||||||
(on_incoming_error_proc)red_channel_client_default_peer_on_error;
|
|
||||||
channel->incoming_cb.on_input = red_channel_client_on_input;
|
|
||||||
channel->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size;
|
|
||||||
channel->outgoing_cb.prepare = red_channel_client_prepare_out_msg;
|
|
||||||
channel->outgoing_cb.on_block = red_channel_client_on_out_block;
|
|
||||||
channel->outgoing_cb.on_error =
|
|
||||||
(on_outgoing_error_proc)red_channel_client_default_peer_on_error;
|
|
||||||
channel->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done;
|
|
||||||
channel->outgoing_cb.on_output = red_channel_client_on_output;
|
|
||||||
|
|
||||||
client_cbs.connect = red_channel_client_default_connect;
|
|
||||||
client_cbs.disconnect = red_channel_client_default_disconnect;
|
|
||||||
client_cbs.migrate = red_channel_client_default_migrate;
|
|
||||||
|
|
||||||
red_channel_register_client_cbs(channel, &client_cbs, NULL);
|
|
||||||
red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER);
|
|
||||||
|
|
||||||
channel->thread_id = pthread_self();
|
|
||||||
|
|
||||||
channel->out_bytes_counter = 0;
|
|
||||||
|
|
||||||
spice_debug("channel type %d id %d thread_id 0x%lx",
|
|
||||||
channel->type, channel->id, channel->thread_id);
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: red_worker can use this one
|
|
||||||
static void dummy_watch_update_mask(SpiceWatch *watch, int event_mask)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static SpiceWatch *dummy_watch_add(const SpiceCoreInterfaceInternal *iface,
|
|
||||||
int fd, int event_mask, SpiceWatchFunc func, void *opaque)
|
|
||||||
{
|
|
||||||
return NULL; // apparently allowed?
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dummy_watch_remove(SpiceWatch *watch)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: actually, since I also use channel_client_dummy, no need for core. Can be NULL
|
|
||||||
static const SpiceCoreInterfaceInternal dummy_core = {
|
|
||||||
.watch_update_mask = dummy_watch_update_mask,
|
|
||||||
.watch_add = dummy_watch_add,
|
|
||||||
.watch_remove = dummy_watch_remove,
|
|
||||||
};
|
|
||||||
|
|
||||||
RedChannel *red_channel_create_dummy(int size, RedsState *reds, uint32_t type, uint32_t id)
|
|
||||||
{
|
|
||||||
RedChannel *channel;
|
|
||||||
ClientCbs client_cbs = { NULL, };
|
|
||||||
|
|
||||||
spice_assert(size >= sizeof(*channel));
|
|
||||||
channel = spice_malloc0(size);
|
|
||||||
channel->type = type;
|
|
||||||
channel->id = id;
|
|
||||||
channel->refs = 1;
|
|
||||||
channel->reds = reds;
|
|
||||||
channel->core = &dummy_core;
|
|
||||||
client_cbs.connect = red_channel_client_default_connect;
|
|
||||||
client_cbs.disconnect = red_channel_client_default_disconnect;
|
|
||||||
client_cbs.migrate = red_channel_client_default_migrate;
|
|
||||||
|
|
||||||
red_channel_register_client_cbs(channel, &client_cbs, NULL);
|
|
||||||
red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER);
|
|
||||||
|
|
||||||
channel->thread_id = pthread_self();
|
|
||||||
spice_debug("channel type %d id %d thread_id 0x%lx",
|
|
||||||
channel->type, channel->id, channel->thread_id);
|
|
||||||
|
|
||||||
channel->out_bytes_counter = 0;
|
|
||||||
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_nothing_handle_message(RedChannelClient *rcc,
|
|
||||||
uint16_t type,
|
|
||||||
uint32_t size,
|
|
||||||
uint8_t *msg)
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
RedChannel *red_channel_create_parser(int size,
|
|
||||||
RedsState *reds,
|
|
||||||
const SpiceCoreInterfaceInternal *core,
|
|
||||||
uint32_t type, uint32_t id,
|
|
||||||
int handle_acks,
|
|
||||||
spice_parse_channel_func_t parser,
|
|
||||||
channel_handle_parsed_proc handle_parsed,
|
|
||||||
const ChannelCbs *channel_cbs,
|
|
||||||
uint32_t migration_flags)
|
|
||||||
{
|
|
||||||
RedChannel *channel = red_channel_create(size, reds, core, type, id,
|
|
||||||
handle_acks,
|
|
||||||
do_nothing_handle_message,
|
|
||||||
channel_cbs,
|
|
||||||
migration_flags);
|
|
||||||
channel->incoming_cb.handle_parsed = (handle_parsed_proc)handle_parsed;
|
|
||||||
channel->incoming_cb.parser = parser;
|
|
||||||
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat)
|
void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat)
|
||||||
{
|
{
|
||||||
spice_return_if_fail(channel != NULL);
|
spice_return_if_fail(channel != NULL);
|
||||||
spice_return_if_fail(channel->stat == 0);
|
spice_return_if_fail(channel->priv->stat == 0);
|
||||||
|
|
||||||
#ifdef RED_STATISTICS
|
#ifdef RED_STATISTICS
|
||||||
channel->stat = stat;
|
channel->priv->stat = stat;
|
||||||
channel->out_bytes_counter = stat_add_counter(channel->reds, stat, "out_bytes", TRUE);
|
channel->priv->out_bytes_counter =
|
||||||
|
stat_add_counter(channel->priv->reds, stat, "out_bytes", TRUE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *client_cbs, gpointer cbs_data)
|
StatNodeRef red_channel_get_stat_node(RedChannel *channel)
|
||||||
{
|
{
|
||||||
spice_assert(client_cbs->connect || channel->type == SPICE_CHANNEL_MAIN);
|
#ifdef RED_STATISTICS
|
||||||
channel->client_cbs.connect = client_cbs->connect;
|
return channel->priv->stat;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *client_cbs,
|
||||||
|
gpointer cbs_data)
|
||||||
|
{
|
||||||
|
spice_assert(client_cbs->connect || channel->priv->type == SPICE_CHANNEL_MAIN);
|
||||||
|
channel->priv->client_cbs.connect = client_cbs->connect;
|
||||||
|
|
||||||
if (client_cbs->disconnect) {
|
if (client_cbs->disconnect) {
|
||||||
channel->client_cbs.disconnect = client_cbs->disconnect;
|
channel->priv->client_cbs.disconnect = client_cbs->disconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client_cbs->migrate) {
|
if (client_cbs->migrate) {
|
||||||
channel->client_cbs.migrate = client_cbs->migrate;
|
channel->priv->client_cbs.migrate = client_cbs->migrate;
|
||||||
}
|
}
|
||||||
channel->data = cbs_data;
|
channel->priv->data = cbs_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap)
|
static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap)
|
||||||
@ -343,32 +483,13 @@ static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap)
|
|||||||
|
|
||||||
void red_channel_set_common_cap(RedChannel *channel, uint32_t cap)
|
void red_channel_set_common_cap(RedChannel *channel, uint32_t cap)
|
||||||
{
|
{
|
||||||
add_capability(&channel->local_caps.common_caps, &channel->local_caps.num_common_caps, cap);
|
add_capability(&channel->priv->local_caps.common_caps,
|
||||||
|
&channel->priv->local_caps.num_common_caps, cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_set_cap(RedChannel *channel, uint32_t cap)
|
void red_channel_set_cap(RedChannel *channel, uint32_t cap)
|
||||||
{
|
{
|
||||||
add_capability(&channel->local_caps.caps, &channel->local_caps.num_caps, cap);
|
add_capability(&channel->priv->local_caps.caps, &channel->priv->local_caps.num_caps, cap);
|
||||||
}
|
|
||||||
|
|
||||||
void red_channel_ref(RedChannel *channel)
|
|
||||||
{
|
|
||||||
channel->refs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void red_channel_unref(RedChannel *channel)
|
|
||||||
{
|
|
||||||
if (--channel->refs == 0) {
|
|
||||||
if (channel->local_caps.num_common_caps) {
|
|
||||||
free(channel->local_caps.common_caps);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel->local_caps.num_caps) {
|
|
||||||
free(channel->local_caps.caps);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(channel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_destroy(RedChannel *channel)
|
void red_channel_destroy(RedChannel *channel)
|
||||||
@ -377,13 +498,13 @@ void red_channel_destroy(RedChannel *channel)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_foreach(channel->clients, (GFunc)red_channel_client_destroy, NULL);
|
g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_destroy, NULL);
|
||||||
red_channel_unref(channel);
|
g_object_unref(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_send(RedChannel *channel)
|
void red_channel_send(RedChannel *channel)
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, (GFunc)red_channel_client_send, NULL);
|
g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_send, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_push(RedChannel *channel)
|
void red_channel_push(RedChannel *channel)
|
||||||
@ -392,14 +513,15 @@ void red_channel_push(RedChannel *channel)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_foreach(channel->clients, (GFunc)red_channel_client_push, NULL);
|
g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_push, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this function doesn't make sense because the window should be client (WAN/LAN)
|
// TODO: this function doesn't make sense because the window should be client (WAN/LAN)
|
||||||
// specific
|
// specific
|
||||||
void red_channel_init_outgoing_messages_window(RedChannel *channel)
|
void red_channel_init_outgoing_messages_window(RedChannel *channel)
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, (GFunc)red_channel_client_init_outgoing_messages_window, NULL);
|
g_list_foreach(channel->priv->clients,
|
||||||
|
(GFunc)red_channel_client_init_outgoing_messages_window, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer user_data)
|
static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer user_data)
|
||||||
@ -410,7 +532,7 @@ static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer user_
|
|||||||
|
|
||||||
void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type)
|
void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type)
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, red_channel_client_pipe_add_type_proxy,
|
g_list_foreach(channel->priv->clients, red_channel_client_pipe_add_type_proxy,
|
||||||
GINT_TO_POINTER(pipe_item_type));
|
GINT_TO_POINTER(pipe_item_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,12 +544,13 @@ static void red_channel_client_pipe_add_empty_msg_proxy(gpointer data, gpointer
|
|||||||
|
|
||||||
void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type)
|
void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type)
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, red_channel_client_pipe_add_empty_msg_proxy, GINT_TO_POINTER(msg_type));
|
g_list_foreach(channel->priv->clients, red_channel_client_pipe_add_empty_msg_proxy,
|
||||||
|
GINT_TO_POINTER(msg_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
int red_channel_is_connected(RedChannel *channel)
|
int red_channel_is_connected(RedChannel *channel)
|
||||||
{
|
{
|
||||||
return channel && channel->clients;
|
return channel && channel->priv->clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc)
|
void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc)
|
||||||
@ -435,19 +558,19 @@ void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc)
|
|||||||
GList *link;
|
GList *link;
|
||||||
g_return_if_fail(channel == red_channel_client_get_channel(rcc));
|
g_return_if_fail(channel == red_channel_client_get_channel(rcc));
|
||||||
|
|
||||||
if (!pthread_equal(pthread_self(), channel->thread_id)) {
|
if (!pthread_equal(pthread_self(), channel->priv->thread_id)) {
|
||||||
spice_warning("channel type %d id %d - "
|
spice_warning("channel type %d id %d - "
|
||||||
"channel->thread_id (0x%lx) != pthread_self (0x%lx)."
|
"channel->thread_id (0x%lx) != pthread_self (0x%lx)."
|
||||||
"If one of the threads is != io-thread && != vcpu-thread, "
|
"If one of the threads is != io-thread && != vcpu-thread, "
|
||||||
"this might be a BUG",
|
"this might be a BUG",
|
||||||
channel->type, channel->id,
|
channel->priv->type, channel->priv->id,
|
||||||
channel->thread_id, pthread_self());
|
channel->priv->thread_id, pthread_self());
|
||||||
}
|
}
|
||||||
spice_return_if_fail(channel);
|
spice_return_if_fail(channel);
|
||||||
link = g_list_find(channel->clients, rcc);
|
link = g_list_find(channel->priv->clients, rcc);
|
||||||
spice_return_if_fail(link != NULL);
|
spice_return_if_fail(link != NULL);
|
||||||
|
|
||||||
channel->clients = g_list_remove_link(channel->clients, link);
|
channel->priv->clients = g_list_remove_link(channel->priv->clients, link);
|
||||||
// TODO: should we set rcc->channel to NULL???
|
// TODO: should we set rcc->channel to NULL???
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,17 +584,35 @@ void red_client_remove_channel(RedChannelClient *rcc)
|
|||||||
|
|
||||||
void red_channel_disconnect(RedChannel *channel)
|
void red_channel_disconnect(RedChannel *channel)
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, (GFunc)red_channel_client_disconnect, NULL);
|
g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_disconnect, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void red_channel_connect(RedChannel *channel, RedClient *client,
|
||||||
|
RedsStream *stream, int migration, int num_common_caps,
|
||||||
|
uint32_t *common_caps, int num_caps, uint32_t *caps)
|
||||||
|
{
|
||||||
|
channel->priv->client_cbs.connect(channel, client, stream, migration,
|
||||||
|
num_common_caps, common_caps, num_caps,
|
||||||
|
caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_apply_clients(RedChannel *channel, channel_client_callback cb)
|
void red_channel_apply_clients(RedChannel *channel, channel_client_callback cb)
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, (GFunc)cb, NULL);
|
g_list_foreach(channel->priv->clients, (GFunc)cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data cb, void *data)
|
void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data cb, void *data)
|
||||||
{
|
{
|
||||||
g_list_foreach(channel->clients, (GFunc)cb, data);
|
g_list_foreach(channel->priv->clients, (GFunc)cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
GList *red_channel_get_clients(RedChannel *channel)
|
||||||
|
{
|
||||||
|
return channel->priv->clients;
|
||||||
|
}
|
||||||
|
guint red_channel_get_n_clients(RedChannel *channel)
|
||||||
|
{
|
||||||
|
return g_list_length(channel->priv->clients);
|
||||||
}
|
}
|
||||||
|
|
||||||
int red_channel_all_blocked(RedChannel *channel)
|
int red_channel_all_blocked(RedChannel *channel)
|
||||||
@ -479,7 +620,7 @@ int red_channel_all_blocked(RedChannel *channel)
|
|||||||
GListIter iter;
|
GListIter iter;
|
||||||
RedChannelClient *rcc;
|
RedChannelClient *rcc;
|
||||||
|
|
||||||
if (!channel || !channel->clients) {
|
if (!channel || !channel->priv->clients) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
FOREACH_CLIENT(channel, iter, rcc) {
|
FOREACH_CLIENT(channel, iter, rcc) {
|
||||||
@ -508,10 +649,10 @@ int red_channel_get_first_socket(RedChannel *channel)
|
|||||||
RedChannelClient *rcc;
|
RedChannelClient *rcc;
|
||||||
RedsStream *stream;
|
RedsStream *stream;
|
||||||
|
|
||||||
if (!channel || !channel->clients) {
|
if (!channel || !channel->priv->clients) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
rcc = g_list_nth_data(channel->clients, 0);
|
rcc = g_list_nth_data(channel->priv->clients, 0);
|
||||||
stream = red_channel_client_get_stream(rcc);
|
stream = red_channel_client_get_stream(rcc);
|
||||||
|
|
||||||
return stream->socket;
|
return stream->socket;
|
||||||
@ -600,7 +741,7 @@ void red_client_migrate(RedClient *client)
|
|||||||
FOREACH_CHANNEL_CLIENT(client, iter, rcc) {
|
FOREACH_CHANNEL_CLIENT(client, iter, rcc) {
|
||||||
channel = red_channel_client_get_channel(rcc);
|
channel = red_channel_client_get_channel(rcc);
|
||||||
if (red_channel_client_is_connected(rcc)) {
|
if (red_channel_client_is_connected(rcc)) {
|
||||||
channel->client_cbs.migrate(rcc);
|
channel->priv->client_cbs.migrate(rcc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -629,7 +770,7 @@ void red_client_destroy(RedClient *client)
|
|||||||
// to wait for disconnection)
|
// to wait for disconnection)
|
||||||
// TODO: should we go back to async. For this we need to use
|
// TODO: should we go back to async. For this we need to use
|
||||||
// ref count for channel clients.
|
// ref count for channel clients.
|
||||||
channel->client_cbs.disconnect(rcc);
|
channel->priv->client_cbs.disconnect(rcc);
|
||||||
spice_assert(red_channel_client_pipe_is_empty(rcc));
|
spice_assert(red_channel_client_pipe_is_empty(rcc));
|
||||||
spice_assert(red_channel_client_no_item_being_sent(rcc));
|
spice_assert(red_channel_client_no_item_being_sent(rcc));
|
||||||
red_channel_client_destroy(rcc);
|
red_channel_client_destroy(rcc);
|
||||||
@ -647,7 +788,7 @@ RedChannelClient *red_client_get_channel(RedClient *client, int type, int id)
|
|||||||
FOREACH_CHANNEL_CLIENT(client, iter, rcc) {
|
FOREACH_CHANNEL_CLIENT(client, iter, rcc) {
|
||||||
RedChannel *channel;
|
RedChannel *channel;
|
||||||
channel = red_channel_client_get_channel(rcc);
|
channel = red_channel_client_get_channel(rcc);
|
||||||
if (channel->type == type && channel->id == id) {
|
if (channel->priv->type == type && channel->priv->id == id) {
|
||||||
ret = rcc;
|
ret = rcc;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -847,5 +988,52 @@ int red_channel_wait_all_sent(RedChannel *channel,
|
|||||||
|
|
||||||
RedsState* red_channel_get_server(RedChannel *channel)
|
RedsState* red_channel_get_server(RedChannel *channel)
|
||||||
{
|
{
|
||||||
return channel->reds;
|
return channel->priv->reds;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpiceCoreInterfaceInternal* red_channel_get_core_interface(RedChannel *channel)
|
||||||
|
{
|
||||||
|
return channel->priv->core;
|
||||||
|
}
|
||||||
|
|
||||||
|
int red_channel_config_socket(RedChannel *self, RedChannelClient *rcc)
|
||||||
|
{
|
||||||
|
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
|
||||||
|
|
||||||
|
return klass->config_socket(rcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void red_channel_on_disconnect(RedChannel *self, RedChannelClient *rcc)
|
||||||
|
{
|
||||||
|
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
|
||||||
|
|
||||||
|
klass->on_disconnect(rcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item)
|
||||||
|
{
|
||||||
|
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self);
|
||||||
|
g_return_if_fail(klass->send_item);
|
||||||
|
|
||||||
|
klass->send_item(rcc, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self)
|
||||||
|
{
|
||||||
|
return &self->priv->incoming_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutgoingHandlerInterface* red_channel_get_outgoing_handler(RedChannel *self)
|
||||||
|
{
|
||||||
|
return &self->priv->outgoing_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void red_channel_reset_thread_id(RedChannel *self)
|
||||||
|
{
|
||||||
|
self->priv->thread_id = pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
const RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *self)
|
||||||
|
{
|
||||||
|
return &self->priv->local_caps;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <glib-object.h>
|
||||||
#include <common/ring.h>
|
#include <common/ring.h>
|
||||||
#include <common/marshaller.h>
|
#include <common/marshaller.h>
|
||||||
|
|
||||||
@ -34,6 +35,8 @@
|
|||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "red-pipe-item.h"
|
#include "red-pipe-item.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
|
typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
|
||||||
|
|
||||||
typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header);
|
typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header);
|
||||||
@ -125,23 +128,6 @@ typedef void (*channel_client_connect_proc)(RedChannel *channel, RedClient *clie
|
|||||||
typedef void (*channel_client_disconnect_proc)(RedChannelClient *base);
|
typedef void (*channel_client_disconnect_proc)(RedChannelClient *base);
|
||||||
typedef void (*channel_client_migrate_proc)(RedChannelClient *base);
|
typedef void (*channel_client_migrate_proc)(RedChannelClient *base);
|
||||||
|
|
||||||
// TODO: add ASSERTS for thread_id in client and channel calls
|
|
||||||
//
|
|
||||||
/*
|
|
||||||
* callbacks that are triggered from channel client stream events.
|
|
||||||
* They are called from the thread that listen to the stream events.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
channel_configure_socket_proc config_socket;
|
|
||||||
channel_disconnect_proc on_disconnect;
|
|
||||||
channel_send_pipe_item_proc send_item;
|
|
||||||
channel_alloc_msg_recv_buf_proc alloc_recv_buf;
|
|
||||||
channel_release_msg_recv_buf_proc release_recv_buf;
|
|
||||||
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark;
|
|
||||||
channel_handle_migrate_data_proc handle_migrate_data;
|
|
||||||
channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial;
|
|
||||||
} ChannelCbs;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* callbacks that are triggered from client events.
|
* callbacks that are triggered from client events.
|
||||||
@ -153,6 +139,63 @@ typedef struct {
|
|||||||
channel_client_migrate_proc migrate;
|
channel_client_migrate_proc migrate;
|
||||||
} ClientCbs;
|
} ClientCbs;
|
||||||
|
|
||||||
|
static inline gboolean test_capability(const uint32_t *caps, int num_caps, uint32_t cap)
|
||||||
|
{
|
||||||
|
return VD_AGENT_HAS_CAPABILITY(caps, num_caps, cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RED_TYPE_CHANNEL red_channel_get_type()
|
||||||
|
|
||||||
|
#define RED_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHANNEL, RedChannel))
|
||||||
|
#define RED_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHANNEL, RedChannelClass))
|
||||||
|
#define RED_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHANNEL))
|
||||||
|
#define RED_IS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHANNEL))
|
||||||
|
#define RED_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHANNEL, RedChannelClass))
|
||||||
|
|
||||||
|
typedef struct RedChannel RedChannel;
|
||||||
|
typedef struct RedChannelClass RedChannelClass;
|
||||||
|
typedef struct RedChannelPrivate RedChannelPrivate;
|
||||||
|
|
||||||
|
struct RedChannel
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
RedChannelPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RedChannelClass
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/* subclasses must implement either handle_message(), or both parser() and
|
||||||
|
* handle_parsed() */
|
||||||
|
channel_handle_message_proc handle_message;
|
||||||
|
spice_parse_channel_func_t parser;
|
||||||
|
channel_handle_parsed_proc handle_parsed;
|
||||||
|
|
||||||
|
// TODO: add ASSERTS for thread_id in client and channel calls
|
||||||
|
/*
|
||||||
|
* callbacks that are triggered from channel client stream events.
|
||||||
|
* They are called from the thread that listen to the stream events.
|
||||||
|
*/
|
||||||
|
channel_configure_socket_proc config_socket;
|
||||||
|
channel_disconnect_proc on_disconnect;
|
||||||
|
channel_send_pipe_item_proc send_item;
|
||||||
|
channel_alloc_msg_recv_buf_proc alloc_recv_buf;
|
||||||
|
channel_release_msg_recv_buf_proc release_recv_buf;
|
||||||
|
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark;
|
||||||
|
channel_handle_migrate_data_proc handle_migrate_data;
|
||||||
|
channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FOREACH_CLIENT(_channel, _iter, _data) \
|
||||||
|
GLIST_FOREACH((_channel ? red_channel_get_clients(RED_CHANNEL(_channel)) : NULL), \
|
||||||
|
_iter, RedChannelClient, _data)
|
||||||
|
|
||||||
|
/* Red Channel interface */
|
||||||
|
|
||||||
typedef struct RedChannelCapabilities {
|
typedef struct RedChannelCapabilities {
|
||||||
int num_common_caps;
|
int num_common_caps;
|
||||||
uint32_t *common_caps;
|
uint32_t *common_caps;
|
||||||
@ -160,100 +203,20 @@ typedef struct RedChannelCapabilities {
|
|||||||
uint32_t *caps;
|
uint32_t *caps;
|
||||||
} RedChannelCapabilities;
|
} RedChannelCapabilities;
|
||||||
|
|
||||||
static inline gboolean test_capability(const uint32_t *caps, int num_caps, uint32_t cap)
|
GType red_channel_get_type(void) G_GNUC_CONST;
|
||||||
{
|
|
||||||
return VD_AGENT_HAS_CAPABILITY(caps, num_caps, cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct RedChannelClientLatencyMonitor {
|
|
||||||
int state;
|
|
||||||
uint64_t last_pong_time;
|
|
||||||
SpiceTimer *timer;
|
|
||||||
uint32_t id;
|
|
||||||
int tcp_nodelay;
|
|
||||||
int warmup_was_sent;
|
|
||||||
|
|
||||||
int64_t roundtrip;
|
|
||||||
} RedChannelClientLatencyMonitor;
|
|
||||||
|
|
||||||
typedef struct RedChannelClientConnectivityMonitor {
|
|
||||||
int state;
|
|
||||||
uint32_t out_bytes;
|
|
||||||
uint32_t in_bytes;
|
|
||||||
uint32_t timeout;
|
|
||||||
SpiceTimer *timer;
|
|
||||||
} RedChannelClientConnectivityMonitor;
|
|
||||||
|
|
||||||
struct RedChannel {
|
|
||||||
uint32_t type;
|
|
||||||
uint32_t id;
|
|
||||||
|
|
||||||
uint32_t refs;
|
|
||||||
|
|
||||||
RingItem link; // channels link for reds
|
|
||||||
|
|
||||||
const SpiceCoreInterfaceInternal *core;
|
|
||||||
int handle_acks;
|
|
||||||
|
|
||||||
// RedChannel will hold only connected channel clients (logic - when pushing pipe item to all channel clients, there
|
|
||||||
// is no need to go over disconnect clients)
|
|
||||||
// . While client will hold the channel clients till it is destroyed
|
|
||||||
// and then it will destroy them as well.
|
|
||||||
// However RCC still holds a reference to the Channel.
|
|
||||||
// Maybe replace these logic with ref count?
|
|
||||||
// TODO: rename to 'connected_clients'?
|
|
||||||
GList *clients;
|
|
||||||
|
|
||||||
OutgoingHandlerInterface outgoing_cb;
|
|
||||||
IncomingHandlerInterface incoming_cb;
|
|
||||||
|
|
||||||
ChannelCbs channel_cbs;
|
|
||||||
ClientCbs client_cbs;
|
|
||||||
|
|
||||||
RedChannelCapabilities local_caps;
|
|
||||||
uint32_t migration_flags;
|
|
||||||
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
// TODO: when different channel_clients are in different threads from Channel -> need to protect!
|
|
||||||
pthread_t thread_id;
|
|
||||||
RedsState *reds;
|
|
||||||
#ifdef RED_STATISTICS
|
|
||||||
StatNodeRef stat;
|
|
||||||
uint64_t *out_bytes_counter;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FOREACH_CLIENT(_channel, _iter, _data) \
|
|
||||||
GLIST_FOREACH((_channel ? RED_CHANNEL(_channel)->clients : NULL), \
|
|
||||||
_iter, RedChannelClient, _data)
|
|
||||||
|
|
||||||
#define RED_CHANNEL(Channel) ((RedChannel *)(Channel))
|
|
||||||
|
|
||||||
/* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
|
|
||||||
* explicitly destroy the channel */
|
|
||||||
RedChannel *red_channel_create(int size,
|
|
||||||
RedsState *reds,
|
|
||||||
const SpiceCoreInterfaceInternal *core,
|
|
||||||
uint32_t type, uint32_t id,
|
|
||||||
int handle_acks,
|
|
||||||
channel_handle_message_proc handle_message,
|
|
||||||
const ChannelCbs *channel_cbs,
|
|
||||||
uint32_t migration_flags);
|
|
||||||
|
|
||||||
/* alternative constructor, meant for marshaller based (inputs,main) channels,
|
/* alternative constructor, meant for marshaller based (inputs,main) channels,
|
||||||
* will become default eventually */
|
* will become default eventually */
|
||||||
|
/*
|
||||||
RedChannel *red_channel_create_parser(int size,
|
RedChannel *red_channel_create_parser(int size,
|
||||||
RedsState *reds,
|
RedsState *reds,
|
||||||
const SpiceCoreInterfaceInternal *core,
|
const SpiceCoreInterfaceInternal *core,
|
||||||
uint32_t type, uint32_t id,
|
uint32_t type, uint32_t id,
|
||||||
int handle_acks,
|
gboolean handle_acks,
|
||||||
spice_parse_channel_func_t parser,
|
spice_parse_channel_func_t parser,
|
||||||
channel_handle_parsed_proc handle_parsed,
|
channel_handle_parsed_proc handle_parsed,
|
||||||
const ChannelCbs *channel_cbs,
|
|
||||||
uint32_t migration_flags);
|
uint32_t migration_flags);
|
||||||
void red_channel_ref(RedChannel *channel);
|
*/
|
||||||
void red_channel_unref(RedChannel *channel);
|
|
||||||
void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc);
|
void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc);
|
||||||
void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc);
|
void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc);
|
||||||
|
|
||||||
@ -264,11 +227,6 @@ void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *clien
|
|||||||
void red_channel_set_common_cap(RedChannel *channel, uint32_t cap);
|
void red_channel_set_common_cap(RedChannel *channel, uint32_t cap);
|
||||||
void red_channel_set_cap(RedChannel *channel, uint32_t cap);
|
void red_channel_set_cap(RedChannel *channel, uint32_t cap);
|
||||||
|
|
||||||
// TODO: tmp, for channels that don't use RedChannel yet (e.g., snd channel), but
|
|
||||||
// do use the client callbacks. So the channel clients are not connected (the channel doesn't
|
|
||||||
// have list of them, but they do have a link to the channel, and the client has a list of them)
|
|
||||||
RedChannel *red_channel_create_dummy(int size, RedsState *reds, uint32_t type, uint32_t id);
|
|
||||||
|
|
||||||
int red_channel_is_connected(RedChannel *channel);
|
int red_channel_is_connected(RedChannel *channel);
|
||||||
|
|
||||||
/* seamless migration is supported for only one client. This routine
|
/* seamless migration is supported for only one client. This routine
|
||||||
@ -332,6 +290,9 @@ void red_channel_receive(RedChannel *channel);
|
|||||||
void red_channel_send(RedChannel *channel);
|
void red_channel_send(RedChannel *channel);
|
||||||
// For red_worker
|
// For red_worker
|
||||||
void red_channel_disconnect(RedChannel *channel);
|
void red_channel_disconnect(RedChannel *channel);
|
||||||
|
void red_channel_connect(RedChannel *channel, RedClient *client,
|
||||||
|
RedsStream *stream, int migration, int num_common_caps,
|
||||||
|
uint32_t *common_caps, int num_caps, uint32_t *caps);
|
||||||
|
|
||||||
/* return the sum of all the rcc pipe size */
|
/* return the sum of all the rcc pipe size */
|
||||||
uint32_t red_channel_max_pipe_size(RedChannel *channel);
|
uint32_t red_channel_max_pipe_size(RedChannel *channel);
|
||||||
@ -344,8 +305,26 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel);
|
|||||||
typedef void (*channel_client_callback)(RedChannelClient *rcc);
|
typedef void (*channel_client_callback)(RedChannelClient *rcc);
|
||||||
typedef void (*channel_client_callback_data)(RedChannelClient *rcc, void *data);
|
typedef void (*channel_client_callback_data)(RedChannelClient *rcc, void *data);
|
||||||
void red_channel_apply_clients(RedChannel *channel, channel_client_callback v);
|
void red_channel_apply_clients(RedChannel *channel, channel_client_callback v);
|
||||||
void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data v, void * data);
|
void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data v,
|
||||||
|
void *data);
|
||||||
|
GList *red_channel_get_clients(RedChannel *channel);
|
||||||
|
guint red_channel_get_n_clients(RedChannel *channel);
|
||||||
struct RedsState* red_channel_get_server(RedChannel *channel);
|
struct RedsState* red_channel_get_server(RedChannel *channel);
|
||||||
|
SpiceCoreInterfaceInternal* red_channel_get_core_interface(RedChannel *channel);
|
||||||
|
|
||||||
|
/* channel callback function */
|
||||||
|
int red_channel_config_socket(RedChannel *self, RedChannelClient *rcc);
|
||||||
|
void red_channel_on_disconnect(RedChannel *self, RedChannelClient *rcc);
|
||||||
|
void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item);
|
||||||
|
void red_channel_reset_thread_id(RedChannel *self);
|
||||||
|
StatNodeRef red_channel_get_stat_node(RedChannel *channel);
|
||||||
|
|
||||||
|
/* FIXME: do these even need to be in RedChannel? It's really only used in
|
||||||
|
* RedChannelClient. Needs refactoring */
|
||||||
|
IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self);
|
||||||
|
OutgoingHandlerInterface* red_channel_get_outgoing_handler(RedChannel *self);
|
||||||
|
|
||||||
|
const RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *self);
|
||||||
|
|
||||||
struct RedClient {
|
struct RedClient {
|
||||||
RedsState *reds;
|
RedsState *reds;
|
||||||
@ -419,4 +398,6 @@ int red_channel_wait_all_sent(RedChannel *channel,
|
|||||||
|
|
||||||
#define CHANNEL_BLOCKED_SLEEP_DURATION 10000 //micro
|
#define CHANNEL_BLOCKED_SLEEP_DURATION 10000 //micro
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -65,6 +65,8 @@ static inline RedDrawable *red_drawable_ref(RedDrawable *drawable)
|
|||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void red_drawable_unref(RedDrawable *red_drawable);
|
||||||
|
|
||||||
typedef struct RedUpdateCmd {
|
typedef struct RedUpdateCmd {
|
||||||
QXLReleaseInfoExt release_info_ext;
|
QXLReleaseInfoExt release_info_ext;
|
||||||
SpiceRect area;
|
SpiceRect area;
|
||||||
|
|||||||
@ -82,7 +82,7 @@ static void red_qxl_set_display_peer(RedChannel *channel, RedClient *client,
|
|||||||
Dispatcher *dispatcher;
|
Dispatcher *dispatcher;
|
||||||
|
|
||||||
spice_debug("%s", "");
|
spice_debug("%s", "");
|
||||||
dispatcher = (Dispatcher *)channel->data;
|
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||||
payload.client = client;
|
payload.client = client;
|
||||||
payload.stream = stream;
|
payload.stream = stream;
|
||||||
payload.migration = migration;
|
payload.migration = migration;
|
||||||
@ -109,7 +109,7 @@ static void red_qxl_disconnect_display_peer(RedChannelClient *rcc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatcher = (Dispatcher *)channel->data;
|
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||||
|
|
||||||
spice_printerr("");
|
spice_printerr("");
|
||||||
payload.rcc = rcc;
|
payload.rcc = rcc;
|
||||||
@ -126,11 +126,14 @@ static void red_qxl_display_migrate(RedChannelClient *rcc)
|
|||||||
RedWorkerMessageDisplayMigrate payload;
|
RedWorkerMessageDisplayMigrate payload;
|
||||||
Dispatcher *dispatcher;
|
Dispatcher *dispatcher;
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
uint32_t type, id;
|
||||||
|
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatcher = (Dispatcher *)channel->data;
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
spice_printerr("channel type %u id %u", channel->type, channel->id);
|
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||||
|
spice_printerr("channel type %u id %u", type, id);
|
||||||
payload.rcc = rcc;
|
payload.rcc = rcc;
|
||||||
dispatcher_send_message(dispatcher,
|
dispatcher_send_message(dispatcher,
|
||||||
RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
|
RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
|
||||||
@ -143,7 +146,7 @@ static void red_qxl_set_cursor_peer(RedChannel *channel, RedClient *client, Reds
|
|||||||
uint32_t *caps)
|
uint32_t *caps)
|
||||||
{
|
{
|
||||||
RedWorkerMessageCursorConnect payload = {0,};
|
RedWorkerMessageCursorConnect payload = {0,};
|
||||||
Dispatcher *dispatcher = (Dispatcher *)channel->data;
|
Dispatcher *dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||||
spice_printerr("");
|
spice_printerr("");
|
||||||
payload.client = client;
|
payload.client = client;
|
||||||
payload.stream = stream;
|
payload.stream = stream;
|
||||||
@ -171,7 +174,7 @@ static void red_qxl_disconnect_cursor_peer(RedChannelClient *rcc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatcher = (Dispatcher *)channel->data;
|
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||||
spice_printerr("");
|
spice_printerr("");
|
||||||
payload.rcc = rcc;
|
payload.rcc = rcc;
|
||||||
|
|
||||||
@ -185,12 +188,14 @@ static void red_qxl_cursor_migrate(RedChannelClient *rcc)
|
|||||||
RedWorkerMessageCursorMigrate payload;
|
RedWorkerMessageCursorMigrate payload;
|
||||||
Dispatcher *dispatcher;
|
Dispatcher *dispatcher;
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
uint32_t type, id;
|
||||||
|
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatcher = (Dispatcher *)channel->data;
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
spice_printerr("channel type %u id %u", channel->type, channel->id);
|
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||||
|
spice_printerr("channel type %u id %u", type, id);
|
||||||
payload.rcc = rcc;
|
payload.rcc = rcc;
|
||||||
dispatcher_send_message(dispatcher,
|
dispatcher_send_message(dispatcher,
|
||||||
RED_WORKER_MESSAGE_CURSOR_MIGRATE,
|
RED_WORKER_MESSAGE_CURSOR_MIGRATE,
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "reds.h"
|
#include "reds.h"
|
||||||
#include "red-worker.h"
|
#include "red-qxl.h"
|
||||||
#include "red-common.h"
|
#include "red-common.h"
|
||||||
#include "memslot.h"
|
#include "memslot.h"
|
||||||
#include "red-parse-qxl.h"
|
#include "red-parse-qxl.h"
|
||||||
|
|||||||
@ -23,16 +23,12 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
@ -93,8 +89,8 @@ struct RedWorker {
|
|||||||
|
|
||||||
static int display_is_connected(RedWorker *worker)
|
static int display_is_connected(RedWorker *worker)
|
||||||
{
|
{
|
||||||
return (worker->display_channel && red_channel_is_connected(
|
return worker->display_channel &&
|
||||||
&worker->display_channel->common.base));
|
red_channel_is_connected(RED_CHANNEL(worker->display_channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
void red_drawable_unref(RedDrawable *red_drawable)
|
void red_drawable_unref(RedDrawable *red_drawable)
|
||||||
@ -261,7 +257,7 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
|
|||||||
spice_error("bad command type");
|
spice_error("bad command type");
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
if (red_channel_all_blocked(&worker->display_channel->common.base)
|
if (red_channel_all_blocked(RED_CHANNEL(worker->display_channel))
|
||||||
|| spice_get_monotonic_time_ns() - start > NSEC_PER_SEC / 100) {
|
|| spice_get_monotonic_time_ns() - start > NSEC_PER_SEC / 100) {
|
||||||
worker->event_timeout = 0;
|
worker->event_timeout = 0;
|
||||||
return n;
|
return n;
|
||||||
@ -404,7 +400,7 @@ static void guest_set_client_capabilities(RedWorker *worker)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((worker->display_channel == NULL) ||
|
if ((worker->display_channel == NULL) ||
|
||||||
(RED_CHANNEL(worker->display_channel)->clients == NULL)) {
|
(red_channel_get_n_clients(RED_CHANNEL(worker->display_channel)) == 0)) {
|
||||||
red_qxl_set_client_capabilities(worker->qxl, FALSE, caps);
|
red_qxl_set_client_capabilities(worker->qxl, FALSE, caps);
|
||||||
} else {
|
} else {
|
||||||
// Take least common denominator
|
// Take least common denominator
|
||||||
@ -541,12 +537,12 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
|
|||||||
if (!worker->driver_cap_monitors_config) {
|
if (!worker->driver_cap_monitors_config) {
|
||||||
red_worker_push_monitors_config(worker);
|
red_worker_push_monitors_config(worker);
|
||||||
}
|
}
|
||||||
red_pipes_add_verb(&worker->display_channel->common.base,
|
red_pipes_add_verb(RED_CHANNEL(worker->display_channel),
|
||||||
SPICE_MSG_DISPLAY_MARK);
|
SPICE_MSG_DISPLAY_MARK);
|
||||||
red_channel_push(&worker->display_channel->common.base);
|
red_channel_push(RED_CHANNEL(worker->display_channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor_channel_init(worker->cursor_channel);
|
cursor_channel_do_init(worker->cursor_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_dev_create_primary_surface(void *opaque, void *payload)
|
static void handle_dev_create_primary_surface(void *opaque, void *payload)
|
||||||
@ -665,7 +661,7 @@ static void handle_dev_oom(void *opaque, void *payload)
|
|||||||
RedWorker *worker = opaque;
|
RedWorker *worker = opaque;
|
||||||
DisplayChannel *display = worker->display_channel;
|
DisplayChannel *display = worker->display_channel;
|
||||||
|
|
||||||
RedChannel *display_red_channel = &display->common.base;
|
RedChannel *display_red_channel = RED_CHANNEL(display);
|
||||||
int ring_is_empty;
|
int ring_is_empty;
|
||||||
|
|
||||||
spice_return_if_fail(worker->running);
|
spice_return_if_fail(worker->running);
|
||||||
@ -1371,6 +1367,7 @@ RedWorker* red_worker_new(QXLInstance *qxl,
|
|||||||
channel = RED_CHANNEL(worker->cursor_channel);
|
channel = RED_CHANNEL(worker->cursor_channel);
|
||||||
red_channel_set_stat_node(channel, stat_add_node(reds, worker->stat, "cursor_channel", TRUE));
|
red_channel_set_stat_node(channel, stat_add_node(reds, worker->stat, "cursor_channel", TRUE));
|
||||||
red_channel_register_client_cbs(channel, client_cursor_cbs, dispatcher);
|
red_channel_register_client_cbs(channel, client_cursor_cbs, dispatcher);
|
||||||
|
g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
|
||||||
reds_register_channel(reds, channel);
|
reds_register_channel(reds, channel);
|
||||||
|
|
||||||
// TODO: handle seemless migration. Temp, setting migrate to FALSE
|
// TODO: handle seemless migration. Temp, setting migrate to FALSE
|
||||||
@ -1378,10 +1375,10 @@ RedWorker* red_worker_new(QXLInstance *qxl,
|
|||||||
reds_get_streaming_video(reds),
|
reds_get_streaming_video(reds),
|
||||||
reds_get_video_codecs(reds),
|
reds_get_video_codecs(reds),
|
||||||
init_info.n_surfaces);
|
init_info.n_surfaces);
|
||||||
|
|
||||||
channel = RED_CHANNEL(worker->display_channel);
|
channel = RED_CHANNEL(worker->display_channel);
|
||||||
red_channel_set_stat_node(channel, stat_add_node(reds, worker->stat, "display_channel", TRUE));
|
red_channel_set_stat_node(channel, stat_add_node(reds, worker->stat, "display_channel", TRUE));
|
||||||
red_channel_register_client_cbs(channel, client_display_cbs, dispatcher);
|
red_channel_register_client_cbs(channel, client_display_cbs, dispatcher);
|
||||||
|
g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
|
||||||
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
|
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
|
||||||
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION);
|
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION);
|
||||||
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
|
red_channel_set_cap(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
|
||||||
@ -1398,8 +1395,8 @@ SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
|
|||||||
spice_assert(MAX_PIPE_SIZE > WIDE_CLIENT_ACK_WINDOW &&
|
spice_assert(MAX_PIPE_SIZE > WIDE_CLIENT_ACK_WINDOW &&
|
||||||
MAX_PIPE_SIZE > NARROW_CLIENT_ACK_WINDOW); //ensure wakeup by ack message
|
MAX_PIPE_SIZE > NARROW_CLIENT_ACK_WINDOW); //ensure wakeup by ack message
|
||||||
|
|
||||||
RED_CHANNEL(worker->cursor_channel)->thread_id = pthread_self();
|
red_channel_reset_thread_id(RED_CHANNEL(worker->cursor_channel));
|
||||||
RED_CHANNEL(worker->display_channel)->thread_id = pthread_self();
|
red_channel_reset_thread_id(RED_CHANNEL(worker->display_channel));
|
||||||
|
|
||||||
GMainLoop *loop = g_main_loop_new(worker->core.main_context, FALSE);
|
GMainLoop *loop = g_main_loop_new(worker->core.main_context, FALSE);
|
||||||
g_main_loop_run(loop);
|
g_main_loop_run(loop);
|
||||||
|
|||||||
@ -30,6 +30,4 @@ RedWorker* red_worker_new(QXLInstance *qxl,
|
|||||||
const ClientCbs *client_display_cbs);
|
const ClientCbs *client_display_cbs);
|
||||||
bool red_worker_run(RedWorker *worker);
|
bool red_worker_run(RedWorker *worker);
|
||||||
|
|
||||||
void red_drawable_unref(RedDrawable *red_drawable);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -114,8 +114,7 @@ struct RedsState {
|
|||||||
between the 2 servers */
|
between the 2 servers */
|
||||||
GList *mig_target_clients;
|
GList *mig_target_clients;
|
||||||
|
|
||||||
int num_of_channels;
|
GList *channels;
|
||||||
Ring channels;
|
|
||||||
int mouse_mode;
|
int mouse_mode;
|
||||||
int is_client_mouse_allowed;
|
int is_client_mouse_allowed;
|
||||||
int dispatcher_allows_client_mouse;
|
int dispatcher_allows_client_mouse;
|
||||||
|
|||||||
@ -455,15 +455,13 @@ void stat_remove_counter(RedsState *reds, uint64_t *counter)
|
|||||||
void reds_register_channel(RedsState *reds, RedChannel *channel)
|
void reds_register_channel(RedsState *reds, RedChannel *channel)
|
||||||
{
|
{
|
||||||
spice_assert(reds);
|
spice_assert(reds);
|
||||||
ring_add(&reds->channels, &channel->link);
|
reds->channels = g_list_prepend(reds->channels, channel);
|
||||||
reds->num_of_channels++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reds_unregister_channel(RedsState *reds, RedChannel *channel)
|
void reds_unregister_channel(RedsState *reds, RedChannel *channel)
|
||||||
{
|
{
|
||||||
if (ring_item_is_linked(&channel->link)) {
|
if (g_list_find(reds->channels, channel)) {
|
||||||
ring_remove(&channel->link);
|
reds->channels = g_list_remove(reds->channels, channel);
|
||||||
reds->num_of_channels--;
|
|
||||||
} else {
|
} else {
|
||||||
spice_warning("not found");
|
spice_warning("not found");
|
||||||
}
|
}
|
||||||
@ -471,11 +469,13 @@ void reds_unregister_channel(RedsState *reds, RedChannel *channel)
|
|||||||
|
|
||||||
static RedChannel *reds_find_channel(RedsState *reds, uint32_t type, uint32_t id)
|
static RedChannel *reds_find_channel(RedsState *reds, uint32_t type, uint32_t id)
|
||||||
{
|
{
|
||||||
RingItem *now;
|
GListIter it;
|
||||||
|
RedChannel *channel;
|
||||||
|
|
||||||
RING_FOREACH(now, &reds->channels) {
|
GLIST_FOREACH(reds->channels, it, RedChannel, channel) {
|
||||||
RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel, link);
|
uint32_t this_type, this_id;
|
||||||
if (channel->type == type && channel->id == id) {
|
g_object_get(channel, "channel-type", &this_type, "id", &this_id, NULL);
|
||||||
|
if (this_type == type && this_id == id) {
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -739,7 +739,7 @@ static void reds_agent_remove(RedsState *reds)
|
|||||||
reds->vdagent = NULL;
|
reds->vdagent = NULL;
|
||||||
reds_update_mouse_mode(reds);
|
reds_update_mouse_mode(reds);
|
||||||
if (reds_main_channel_connected(reds) &&
|
if (reds_main_channel_connected(reds) &&
|
||||||
!red_channel_is_waiting_for_migrate_data(&reds->main_channel->base)) {
|
!red_channel_is_waiting_for_migrate_data(RED_CHANNEL(reds->main_channel))) {
|
||||||
main_channel_push_agent_disconnected(reds->main_channel);
|
main_channel_push_agent_disconnected(reds->main_channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -983,7 +983,9 @@ SPICE_GNUC_VISIBLE int spice_server_get_num_clients(SpiceServer *reds)
|
|||||||
|
|
||||||
static int channel_supports_multiple_clients(RedChannel *channel)
|
static int channel_supports_multiple_clients(RedChannel *channel)
|
||||||
{
|
{
|
||||||
switch (channel->type) {
|
uint32_t type;
|
||||||
|
g_object_get(channel, "channel-type", &type, NULL);
|
||||||
|
switch (type) {
|
||||||
case SPICE_CHANNEL_MAIN:
|
case SPICE_CHANNEL_MAIN:
|
||||||
case SPICE_CHANNEL_DISPLAY:
|
case SPICE_CHANNEL_DISPLAY:
|
||||||
case SPICE_CHANNEL_CURSOR:
|
case SPICE_CHANNEL_CURSOR:
|
||||||
@ -995,23 +997,25 @@ static int channel_supports_multiple_clients(RedChannel *channel)
|
|||||||
|
|
||||||
static void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info)
|
static void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info)
|
||||||
{
|
{
|
||||||
RingItem *now;
|
GListIter it;
|
||||||
|
RedChannel *channel;
|
||||||
int used_channels = 0;
|
int used_channels = 0;
|
||||||
|
|
||||||
RING_FOREACH(now, &reds->channels) {
|
GLIST_FOREACH(reds->channels, it, RedChannel, channel) {
|
||||||
RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel, link);
|
uint32_t type, id;
|
||||||
if (reds->num_clients > 1 &&
|
if (reds->num_clients > 1 &&
|
||||||
!channel_supports_multiple_clients(channel)) {
|
!channel_supports_multiple_clients(channel)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
channels_info->channels[used_channels].type = channel->type;
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
channels_info->channels[used_channels].id = channel->id;
|
channels_info->channels[used_channels].type = type;
|
||||||
|
channels_info->channels[used_channels].id = id;
|
||||||
used_channels++;
|
used_channels++;
|
||||||
}
|
}
|
||||||
|
|
||||||
channels_info->num_of_channels = used_channels;
|
channels_info->num_of_channels = used_channels;
|
||||||
if (used_channels != reds->num_of_channels) {
|
if (used_channels != g_list_length(reds->channels)) {
|
||||||
spice_warning("sent %d out of %d", used_channels, reds->num_of_channels);
|
spice_warning("sent %d out of %d", used_channels, g_list_length(reds->channels));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1022,7 +1026,7 @@ SpiceMsgChannels *reds_msg_channels_new(RedsState *reds)
|
|||||||
spice_assert(reds != NULL);
|
spice_assert(reds != NULL);
|
||||||
|
|
||||||
channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels)
|
channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels)
|
||||||
+ reds->num_of_channels * sizeof(SpiceChannelId));
|
+ g_list_length(reds->channels) * sizeof(SpiceChannelId));
|
||||||
|
|
||||||
reds_fill_channels(reds, channels_info);
|
reds_fill_channels(reds, channels_info);
|
||||||
|
|
||||||
@ -1522,7 +1526,7 @@ static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
|
|||||||
SpiceLinkHeader header;
|
SpiceLinkHeader header;
|
||||||
SpiceLinkReply ack;
|
SpiceLinkReply ack;
|
||||||
RedChannel *channel;
|
RedChannel *channel;
|
||||||
RedChannelCapabilities *channel_caps;
|
const RedChannelCapabilities *channel_caps;
|
||||||
BUF_MEM *bmBuf;
|
BUF_MEM *bmBuf;
|
||||||
BIO *bio = NULL;
|
BIO *bio = NULL;
|
||||||
int ret = FALSE;
|
int ret = FALSE;
|
||||||
@ -1543,12 +1547,12 @@ static int reds_send_link_ack(RedsState *reds, RedLinkInfo *link)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
spice_assert(reds->main_channel);
|
spice_assert(reds->main_channel);
|
||||||
channel = &reds->main_channel->base;
|
channel = RED_CHANNEL(reds->main_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
reds_channel_init_auth_caps(link, channel); /* make sure common caps are set */
|
reds_channel_init_auth_caps(link, channel); /* make sure common caps are set */
|
||||||
|
|
||||||
channel_caps = &channel->local_caps;
|
channel_caps = red_channel_get_local_capabilities(channel);
|
||||||
ack.num_common_caps = GUINT32_TO_LE(channel_caps->num_common_caps);
|
ack.num_common_caps = GUINT32_TO_LE(channel_caps->num_common_caps);
|
||||||
ack.num_channel_caps = GUINT32_TO_LE(channel_caps->num_caps);
|
ack.num_channel_caps = GUINT32_TO_LE(channel_caps->num_caps);
|
||||||
hdr_size += channel_caps->num_common_caps * sizeof(uint32_t);
|
hdr_size += channel_caps->num_common_caps * sizeof(uint32_t);
|
||||||
@ -1856,13 +1860,13 @@ static void reds_channel_do_link(RedChannel *channel, RedClient *client,
|
|||||||
spice_assert(stream);
|
spice_assert(stream);
|
||||||
|
|
||||||
caps = (uint32_t *)((uint8_t *)link_msg + link_msg->caps_offset);
|
caps = (uint32_t *)((uint8_t *)link_msg + link_msg->caps_offset);
|
||||||
channel->client_cbs.connect(channel, client, stream,
|
red_channel_connect(channel, client, stream,
|
||||||
red_client_during_migrate_at_target(client),
|
red_client_during_migrate_at_target(client),
|
||||||
link_msg->num_common_caps,
|
link_msg->num_common_caps,
|
||||||
link_msg->num_common_caps ? caps : NULL,
|
link_msg->num_common_caps ? caps : NULL,
|
||||||
link_msg->num_channel_caps,
|
link_msg->num_channel_caps,
|
||||||
link_msg->num_channel_caps ?
|
link_msg->num_channel_caps ?
|
||||||
caps + link_msg->num_common_caps : NULL);
|
caps + link_msg->num_common_caps : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3106,7 +3110,7 @@ static RedCharDevice *attach_to_red_agent(RedsState *reds, SpiceCharDeviceInstan
|
|||||||
dev->priv->plug_generation++;
|
dev->priv->plug_generation++;
|
||||||
|
|
||||||
if (dev->priv->mig_data ||
|
if (dev->priv->mig_data ||
|
||||||
red_channel_is_waiting_for_migrate_data(&reds->main_channel->base)) {
|
red_channel_is_waiting_for_migrate_data(RED_CHANNEL(reds->main_channel))) {
|
||||||
/* Migration in progress (code is running on the destination host):
|
/* Migration in progress (code is running on the destination host):
|
||||||
* 1. Add the client to spice char device, if it was not already added.
|
* 1. Add the client to spice char device, if it was not already added.
|
||||||
* 2.a If this (qemu-kvm state load side of migration) happens first
|
* 2.a If this (qemu-kvm state load side of migration) happens first
|
||||||
@ -3430,7 +3434,7 @@ static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface)
|
|||||||
ring_init(&reds->clients);
|
ring_init(&reds->clients);
|
||||||
reds->num_clients = 0;
|
reds->num_clients = 0;
|
||||||
reds->main_dispatcher = main_dispatcher_new(reds, reds->core);
|
reds->main_dispatcher = main_dispatcher_new(reds, reds->core);
|
||||||
ring_init(&reds->channels);
|
reds->channels = NULL;
|
||||||
reds->mig_target_clients = NULL;
|
reds->mig_target_clients = NULL;
|
||||||
reds->char_devices = NULL;
|
reds->char_devices = NULL;
|
||||||
reds->mig_wait_disconnect_clients = NULL;
|
reds->mig_wait_disconnect_clients = NULL;
|
||||||
@ -4090,7 +4094,7 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *reds, const cha
|
|||||||
* be valid (see reds_reset_vdp for more details).
|
* be valid (see reds_reset_vdp for more details).
|
||||||
*/
|
*/
|
||||||
try_seamless = reds->seamless_migration_enabled &&
|
try_seamless = reds->seamless_migration_enabled &&
|
||||||
red_channel_test_remote_cap(&reds->main_channel->base,
|
red_channel_test_remote_cap(RED_CHANNEL(reds->main_channel),
|
||||||
SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS);
|
SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS);
|
||||||
/* main channel will take care of clients that are still during migration (at target)*/
|
/* main channel will take care of clients that are still during migration (at target)*/
|
||||||
if (main_channel_migrate_connect(reds->main_channel, reds->config->mig_spice,
|
if (main_channel_migrate_connect(reds->main_channel, reds->config->mig_spice,
|
||||||
|
|||||||
@ -49,9 +49,61 @@
|
|||||||
// Maximal length of APDU
|
// Maximal length of APDU
|
||||||
#define APDUBufSize 270
|
#define APDUBufSize 270
|
||||||
|
|
||||||
|
#define RED_TYPE_SMARTCARD_CHANNEL red_smartcard_channel_get_type()
|
||||||
|
|
||||||
|
#define RED_SMARTCARD_CHANNEL(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_SMARTCARD_CHANNEL, RedSmartcardChannel))
|
||||||
|
#define RED_SMARTCARD_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_SMARTCARD_CHANNEL, RedSmartcardChannelClass))
|
||||||
|
#define RED_IS_SMARTCARD_CHANNEL(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_SMARTCARD_CHANNEL))
|
||||||
|
#define RED_IS_SMARTCARD_CHANNEL_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_SMARTCARD_CHANNEL))
|
||||||
|
#define RED_SMARTCARD_CHANNEL_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_SMARTCARD_CHANNEL, RedSmartcardChannelClass))
|
||||||
|
|
||||||
|
typedef struct RedSmartcardChannel RedSmartcardChannel;
|
||||||
|
typedef struct RedSmartcardChannelClass RedSmartcardChannelClass;
|
||||||
|
|
||||||
|
struct RedSmartcardChannel
|
||||||
|
{
|
||||||
|
RedChannel parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RedSmartcardChannelClass
|
||||||
|
{
|
||||||
|
RedChannelClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType red_smartcard_channel_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(RedSmartcardChannel, red_smartcard_channel, RED_TYPE_CHANNEL)
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_smartcard_channel_init(RedSmartcardChannel *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static RedSmartcardChannel *
|
||||||
|
red_smartcard_channel_new(RedsState *reds)
|
||||||
|
{
|
||||||
|
return g_object_new(RED_TYPE_SMARTCARD_CHANNEL,
|
||||||
|
"spice-server", reds,
|
||||||
|
"core-interface", reds_get_core_interface(reds),
|
||||||
|
"channel-type", SPICE_CHANNEL_SMARTCARD,
|
||||||
|
"id", 0,
|
||||||
|
"handle-acks", FALSE /* handle_acks */,
|
||||||
|
"migration-flags",
|
||||||
|
(SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE(RedCharDeviceSmartcard, red_char_device_smartcard, RED_TYPE_CHAR_DEVICE)
|
G_DEFINE_TYPE(RedCharDeviceSmartcard, red_char_device_smartcard, RED_TYPE_CHAR_DEVICE)
|
||||||
|
|
||||||
#define RED_CHAR_DEVICE_SMARTCARD_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_SMARTCARD, RedCharDeviceSmartcardPrivate))
|
#define RED_CHAR_DEVICE_SMARTCARD_PRIVATE(o) \
|
||||||
|
(G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_SMARTCARD, \
|
||||||
|
RedCharDeviceSmartcardPrivate))
|
||||||
|
|
||||||
struct RedCharDeviceSmartcardPrivate {
|
struct RedCharDeviceSmartcardPrivate {
|
||||||
uint32_t reader_id;
|
uint32_t reader_id;
|
||||||
@ -74,10 +126,6 @@ typedef struct RedMsgItem {
|
|||||||
static RedMsgItem *smartcard_get_vsc_msg_item(RedChannelClient *rcc, VSCMsgHeader *vheader);
|
static RedMsgItem *smartcard_get_vsc_msg_item(RedChannelClient *rcc, VSCMsgHeader *vheader);
|
||||||
static void smartcard_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item);
|
static void smartcard_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item);
|
||||||
|
|
||||||
typedef struct SmartCardChannel {
|
|
||||||
RedChannel base;
|
|
||||||
} SmartCardChannel;
|
|
||||||
|
|
||||||
static struct Readers {
|
static struct Readers {
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
SpiceCharDeviceInstance* sin[SMARTCARD_MAX_READERS];
|
SpiceCharDeviceInstance* sin[SMARTCARD_MAX_READERS];
|
||||||
@ -519,41 +567,49 @@ static void smartcard_connect_client(RedChannel *channel, RedClient *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SmartCardChannel *g_smartcard_channel;
|
static void
|
||||||
|
red_smartcard_channel_constructed(GObject *object)
|
||||||
|
{
|
||||||
|
RedSmartcardChannel *self = RED_SMARTCARD_CHANNEL(object);
|
||||||
|
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
|
||||||
|
ClientCbs client_cbs = { NULL, };
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(red_smartcard_channel_parent_class)->constructed(object);
|
||||||
|
|
||||||
|
client_cbs.connect = smartcard_connect_client;
|
||||||
|
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
|
||||||
|
|
||||||
|
reds_register_channel(reds, RED_CHANNEL(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
red_smartcard_channel_class_init(RedSmartcardChannelClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->constructed = red_smartcard_channel_constructed;
|
||||||
|
|
||||||
|
channel_class->handle_message = smartcard_channel_client_handle_message,
|
||||||
|
|
||||||
|
channel_class->config_socket = smartcard_channel_client_config_socket;
|
||||||
|
channel_class->on_disconnect = smartcard_channel_client_on_disconnect;
|
||||||
|
channel_class->send_item = smartcard_channel_send_item;
|
||||||
|
channel_class->alloc_recv_buf = smartcard_channel_client_alloc_msg_rcv_buf;
|
||||||
|
channel_class->release_recv_buf = smartcard_channel_client_release_msg_rcv_buf;
|
||||||
|
channel_class->handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark;
|
||||||
|
channel_class->handle_migrate_data = smartcard_channel_client_handle_migrate_data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: remove global */
|
||||||
|
RedSmartcardChannel *g_smartcard_channel;
|
||||||
|
|
||||||
static void smartcard_init(RedsState *reds)
|
static void smartcard_init(RedsState *reds)
|
||||||
{
|
{
|
||||||
ChannelCbs channel_cbs = { NULL, };
|
|
||||||
ClientCbs client_cbs = { NULL, };
|
|
||||||
uint32_t migration_flags = SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER;
|
|
||||||
|
|
||||||
spice_assert(!g_smartcard_channel);
|
spice_assert(!g_smartcard_channel);
|
||||||
|
|
||||||
channel_cbs.config_socket = smartcard_channel_client_config_socket;
|
g_smartcard_channel = red_smartcard_channel_new(reds);
|
||||||
channel_cbs.on_disconnect = smartcard_channel_client_on_disconnect;
|
|
||||||
channel_cbs.send_item = smartcard_channel_send_item;
|
|
||||||
channel_cbs.alloc_recv_buf = smartcard_channel_client_alloc_msg_rcv_buf;
|
|
||||||
channel_cbs.release_recv_buf = smartcard_channel_client_release_msg_rcv_buf;
|
|
||||||
channel_cbs.handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark;
|
|
||||||
channel_cbs.handle_migrate_data = smartcard_channel_client_handle_migrate_data;
|
|
||||||
|
|
||||||
g_smartcard_channel = (SmartCardChannel*)red_channel_create(sizeof(SmartCardChannel),
|
|
||||||
reds,
|
|
||||||
reds_get_core_interface(reds),
|
|
||||||
SPICE_CHANNEL_SMARTCARD, 0,
|
|
||||||
FALSE /* handle_acks */,
|
|
||||||
smartcard_channel_client_handle_message,
|
|
||||||
&channel_cbs,
|
|
||||||
migration_flags);
|
|
||||||
|
|
||||||
if (!g_smartcard_channel) {
|
|
||||||
spice_error("failed to allocate Smartcard Channel");
|
|
||||||
}
|
|
||||||
|
|
||||||
client_cbs.connect = smartcard_connect_client;
|
|
||||||
red_channel_register_client_cbs(&g_smartcard_channel->base, &client_cbs, NULL);
|
|
||||||
|
|
||||||
reds_register_channel(reds, &g_smartcard_channel->base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "spice.h"
|
#include "spice.h"
|
||||||
#include "red-common.h"
|
#include "red-common.h"
|
||||||
|
#include "dummy-channel.h"
|
||||||
#include "dummy-channel-client.h"
|
#include "dummy-channel-client.h"
|
||||||
#include "main-channel.h"
|
#include "main-channel.h"
|
||||||
#include "reds.h"
|
#include "reds.h"
|
||||||
@ -218,6 +219,7 @@ static void snd_disconnect_channel(SndChannel *channel)
|
|||||||
SndWorker *worker;
|
SndWorker *worker;
|
||||||
RedsState *reds;
|
RedsState *reds;
|
||||||
RedChannel *red_channel;
|
RedChannel *red_channel;
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
if (!channel || !channel->stream) {
|
if (!channel || !channel->stream) {
|
||||||
spice_debug("not connected");
|
spice_debug("not connected");
|
||||||
@ -225,8 +227,9 @@ static void snd_disconnect_channel(SndChannel *channel)
|
|||||||
}
|
}
|
||||||
red_channel = red_channel_client_get_channel(channel->channel_client);
|
red_channel = red_channel_client_get_channel(channel->channel_client);
|
||||||
reds = snd_channel_get_server(channel);
|
reds = snd_channel_get_server(channel);
|
||||||
|
g_object_get(red_channel, "channel-type", &type, NULL);
|
||||||
spice_debug("SndChannel=%p rcc=%p type=%d",
|
spice_debug("SndChannel=%p rcc=%p type=%d",
|
||||||
channel, channel->channel_client, red_channel->type);
|
channel, channel->channel_client, type);
|
||||||
worker = channel->worker;
|
worker = channel->worker;
|
||||||
channel->cleanup(channel);
|
channel->cleanup(channel);
|
||||||
red_channel_client_disconnect(worker->connection->channel_client);
|
red_channel_client_disconnect(worker->connection->channel_client);
|
||||||
@ -998,12 +1001,14 @@ static void snd_disconnect_channel_client(RedChannelClient *rcc)
|
|||||||
{
|
{
|
||||||
SndWorker *worker;
|
SndWorker *worker;
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
spice_assert(channel);
|
spice_assert(channel);
|
||||||
spice_assert(channel->data);
|
worker = (SndWorker *)g_object_get_data(G_OBJECT(channel), "sound-worker");
|
||||||
worker = (SndWorker *)channel->data;
|
spice_assert(worker);
|
||||||
|
g_object_get(channel, "channel-type", &type, NULL);
|
||||||
|
|
||||||
spice_debug("channel-type=%d", channel->type);
|
spice_debug("channel-type=%d", type);
|
||||||
if (worker->connection) {
|
if (worker->connection) {
|
||||||
spice_assert(worker->connection->channel_client == rcc);
|
spice_assert(worker->connection->channel_client == rcc);
|
||||||
snd_disconnect_channel(worker->connection);
|
snd_disconnect_channel(worker->connection);
|
||||||
@ -1145,7 +1150,9 @@ void snd_set_playback_latency(RedClient *client, uint32_t latency)
|
|||||||
SndWorker *now = workers;
|
SndWorker *now = workers;
|
||||||
|
|
||||||
for (; now; now = now->next) {
|
for (; now; now = now->next) {
|
||||||
if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK && now->connection &&
|
uint32_t type;
|
||||||
|
g_object_get(now->base_channel, "channel-type", &type, NULL);
|
||||||
|
if (type == SPICE_CHANNEL_PLAYBACK && now->connection &&
|
||||||
red_channel_client_get_client(now->connection->channel_client) == client) {
|
red_channel_client_get_client(now->connection->channel_client) == client) {
|
||||||
|
|
||||||
if (red_channel_client_test_remote_cap(now->connection->channel_client,
|
if (red_channel_client_test_remote_cap(now->connection->channel_client,
|
||||||
@ -1213,7 +1220,7 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt
|
|||||||
int migration, int num_common_caps, uint32_t *common_caps,
|
int migration, int num_common_caps, uint32_t *common_caps,
|
||||||
int num_caps, uint32_t *caps)
|
int num_caps, uint32_t *caps)
|
||||||
{
|
{
|
||||||
SndWorker *worker = channel->data;
|
SndWorker *worker = g_object_get_data(G_OBJECT(channel), "sound-worker");
|
||||||
PlaybackChannel *playback_channel;
|
PlaybackChannel *playback_channel;
|
||||||
SpicePlaybackState *st = SPICE_CONTAINEROF(worker, SpicePlaybackState, worker);
|
SpicePlaybackState *st = SPICE_CONTAINEROF(worker, SpicePlaybackState, worker);
|
||||||
|
|
||||||
@ -1242,7 +1249,8 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt
|
|||||||
SPICE_PLAYBACK_CAP_CELT_0_5_1);
|
SPICE_PLAYBACK_CAP_CELT_0_5_1);
|
||||||
int client_can_opus = red_channel_client_test_remote_cap(playback_channel->base.channel_client,
|
int client_can_opus = red_channel_client_test_remote_cap(playback_channel->base.channel_client,
|
||||||
SPICE_PLAYBACK_CAP_OPUS);
|
SPICE_PLAYBACK_CAP_OPUS);
|
||||||
int playback_compression = reds_config_get_playback_compression(channel->reds);
|
int playback_compression =
|
||||||
|
reds_config_get_playback_compression(red_channel_get_server(channel));
|
||||||
int desired_mode = snd_desired_audio_mode(playback_compression, st->frequency,
|
int desired_mode = snd_desired_audio_mode(playback_compression, st->frequency,
|
||||||
client_can_celt, client_can_opus);
|
client_can_celt, client_can_opus);
|
||||||
playback_channel->mode = SPICE_AUDIO_DATA_MODE_RAW;
|
playback_channel->mode = SPICE_AUDIO_DATA_MODE_RAW;
|
||||||
@ -1271,8 +1279,8 @@ static void snd_record_migrate_channel_client(RedChannelClient *rcc)
|
|||||||
|
|
||||||
spice_debug(NULL);
|
spice_debug(NULL);
|
||||||
spice_assert(channel);
|
spice_assert(channel);
|
||||||
spice_assert(channel->data);
|
worker = (SndWorker *)g_object_get_data(G_OBJECT(channel), "sound-worker");
|
||||||
worker = (SndWorker *)channel->data;
|
spice_assert(worker);
|
||||||
|
|
||||||
if (worker->connection) {
|
if (worker->connection) {
|
||||||
spice_assert(worker->connection->channel_client == rcc);
|
spice_assert(worker->connection->channel_client == rcc);
|
||||||
@ -1462,7 +1470,7 @@ static void snd_set_record_peer(RedChannel *channel, RedClient *client, RedsStre
|
|||||||
int migration, int num_common_caps, uint32_t *common_caps,
|
int migration, int num_common_caps, uint32_t *common_caps,
|
||||||
int num_caps, uint32_t *caps)
|
int num_caps, uint32_t *caps)
|
||||||
{
|
{
|
||||||
SndWorker *worker = channel->data;
|
SndWorker *worker = g_object_get_data(G_OBJECT(channel), "sound-worker");
|
||||||
RecordChannel *record_channel;
|
RecordChannel *record_channel;
|
||||||
SpiceRecordState *st = SPICE_CONTAINEROF(worker, SpiceRecordState, worker);
|
SpiceRecordState *st = SPICE_CONTAINEROF(worker, SpiceRecordState, worker);
|
||||||
|
|
||||||
@ -1500,8 +1508,8 @@ static void snd_playback_migrate_channel_client(RedChannelClient *rcc)
|
|||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
|
||||||
spice_assert(channel);
|
spice_assert(channel);
|
||||||
spice_assert(channel->data);
|
worker = (SndWorker *)g_object_get_data(G_OBJECT(channel), "sound-worker");
|
||||||
worker = (SndWorker *)channel->data;
|
spice_assert(worker);
|
||||||
spice_debug(NULL);
|
spice_debug(NULL);
|
||||||
|
|
||||||
if (worker->connection) {
|
if (worker->connection) {
|
||||||
@ -1542,8 +1550,9 @@ void snd_attach_playback(RedsState *reds, SpicePlaybackInstance *sin)
|
|||||||
sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to the legacy rate */
|
sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to the legacy rate */
|
||||||
|
|
||||||
// TODO: Make RedChannel base of worker? instead of assigning it to channel->data
|
// TODO: Make RedChannel base of worker? instead of assigning it to channel->data
|
||||||
channel = red_channel_create_dummy(sizeof(RedChannel), reds, SPICE_CHANNEL_PLAYBACK, 0);
|
channel = dummy_channel_new(reds, SPICE_CHANNEL_PLAYBACK, 0);
|
||||||
|
|
||||||
|
g_object_set_data(G_OBJECT(channel), "sound-worker", playback_worker);
|
||||||
client_cbs.connect = snd_set_playback_peer;
|
client_cbs.connect = snd_set_playback_peer;
|
||||||
client_cbs.disconnect = snd_disconnect_channel_client;
|
client_cbs.disconnect = snd_disconnect_channel_client;
|
||||||
client_cbs.migrate = snd_playback_migrate_channel_client;
|
client_cbs.migrate = snd_playback_migrate_channel_client;
|
||||||
@ -1571,8 +1580,9 @@ void snd_attach_record(RedsState *reds, SpiceRecordInstance *sin)
|
|||||||
sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to the legacy rate */
|
sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to the legacy rate */
|
||||||
|
|
||||||
// TODO: Make RedChannel base of worker? instead of assigning it to channel->data
|
// TODO: Make RedChannel base of worker? instead of assigning it to channel->data
|
||||||
channel = red_channel_create_dummy(sizeof(RedChannel), reds, SPICE_CHANNEL_RECORD, 0);
|
channel = dummy_channel_new(reds, SPICE_CHANNEL_RECORD, 0);
|
||||||
|
|
||||||
|
g_object_set_data(G_OBJECT(channel), "sound-worker", record_worker);
|
||||||
client_cbs.connect = snd_set_record_peer;
|
client_cbs.connect = snd_set_record_peer;
|
||||||
client_cbs.disconnect = snd_disconnect_channel_client;
|
client_cbs.disconnect = snd_disconnect_channel_client;
|
||||||
client_cbs.migrate = snd_record_migrate_channel_client;
|
client_cbs.migrate = snd_record_migrate_channel_client;
|
||||||
@ -1628,7 +1638,9 @@ void snd_set_playback_compression(int on)
|
|||||||
SndWorker *now = workers;
|
SndWorker *now = workers;
|
||||||
|
|
||||||
for (; now; now = now->next) {
|
for (; now; now = now->next) {
|
||||||
if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK && now->connection) {
|
uint32_t type;
|
||||||
|
g_object_get(now->base_channel, "channel-type", &type, NULL);
|
||||||
|
if (type == SPICE_CHANNEL_PLAYBACK && now->connection) {
|
||||||
PlaybackChannel* playback = (PlaybackChannel*)now->connection;
|
PlaybackChannel* playback = (PlaybackChannel*)now->connection;
|
||||||
SpicePlaybackState *st = SPICE_CONTAINEROF(now, SpicePlaybackState, worker);
|
SpicePlaybackState *st = SPICE_CONTAINEROF(now, SpicePlaybackState, worker);
|
||||||
int client_can_celt = red_channel_client_test_remote_cap(playback->base.channel_client,
|
int client_can_celt = red_channel_client_test_remote_cap(playback->base.channel_client,
|
||||||
|
|||||||
@ -57,23 +57,18 @@ typedef struct RedVmcPipeItem {
|
|||||||
uint32_t buf_used;
|
uint32_t buf_used;
|
||||||
} RedVmcPipeItem;
|
} RedVmcPipeItem;
|
||||||
|
|
||||||
typedef struct SpiceVmcState {
|
|
||||||
RedChannel channel; /* Must be the first item */
|
|
||||||
RedChannelClient *rcc;
|
|
||||||
RedCharDevice *chardev;
|
|
||||||
SpiceCharDeviceInstance *chardev_sin;
|
|
||||||
RedVmcPipeItem *pipe_item;
|
|
||||||
RedCharDeviceWriteBuffer *recv_from_client_buf;
|
|
||||||
uint8_t port_opened;
|
|
||||||
} SpiceVmcState;
|
|
||||||
|
|
||||||
#define RED_TYPE_CHAR_DEVICE_SPICEVMC red_char_device_spicevmc_get_type()
|
#define RED_TYPE_CHAR_DEVICE_SPICEVMC red_char_device_spicevmc_get_type()
|
||||||
|
|
||||||
#define RED_CHAR_DEVICE_SPICEVMC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmc))
|
#define RED_CHAR_DEVICE_SPICEVMC(obj) \
|
||||||
#define RED_CHAR_DEVICE_SPICEVMC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmcClass))
|
(G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmc))
|
||||||
#define RED_IS_CHAR_DEVICE_SPICEVMC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC))
|
#define RED_CHAR_DEVICE_SPICEVMC_CLASS(klass) \
|
||||||
#define RED_IS_CHAR_DEVICE_SPICEVMC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHAR_DEVICE_SPICEVMC))
|
(G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmcClass))
|
||||||
#define RED_CHAR_DEVICE_SPICEVMC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmcClass))
|
#define RED_IS_CHAR_DEVICE_SPICEVMC(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC))
|
||||||
|
#define RED_IS_CHAR_DEVICE_SPICEVMC_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHAR_DEVICE_SPICEVMC))
|
||||||
|
#define RED_CHAR_DEVICE_SPICEVMC_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmcClass))
|
||||||
|
|
||||||
typedef struct RedCharDeviceSpiceVmc RedCharDeviceSpiceVmc;
|
typedef struct RedCharDeviceSpiceVmc RedCharDeviceSpiceVmc;
|
||||||
typedef struct RedCharDeviceSpiceVmcClass RedCharDeviceSpiceVmcClass;
|
typedef struct RedCharDeviceSpiceVmcClass RedCharDeviceSpiceVmcClass;
|
||||||
@ -94,6 +89,202 @@ static RedCharDevice *red_char_device_spicevmc_new(SpiceCharDeviceInstance *sin,
|
|||||||
|
|
||||||
G_DEFINE_TYPE(RedCharDeviceSpiceVmc, red_char_device_spicevmc, RED_TYPE_CHAR_DEVICE)
|
G_DEFINE_TYPE(RedCharDeviceSpiceVmc, red_char_device_spicevmc, RED_TYPE_CHAR_DEVICE)
|
||||||
|
|
||||||
|
#define RED_CHAR_DEVICE_SPICEVMC_PRIVATE(o) \
|
||||||
|
(G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmcPrivate))
|
||||||
|
|
||||||
|
#define SPICE_TYPE_VMC_STATE spice_vmc_state_get_type()
|
||||||
|
|
||||||
|
#define SPICE_VMC_STATE(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj), SPICE_TYPE_VMC_STATE, SpiceVmcState))
|
||||||
|
#define SPICE_VMC_STATE_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass), SPICE_TYPE_VMC_STATE, SpiceVmcStateClass))
|
||||||
|
#define SPICE_IS_VMC_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), SPICE_TYPE_VMC_STATE))
|
||||||
|
#define SPICE_IS_VMC_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SPICE_TYPE_VMC_STATE))
|
||||||
|
#define SPICE_VMC_STATE_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS((obj), SPICE_TYPE_VMC_STATE, SpiceVmcStateClass))
|
||||||
|
|
||||||
|
typedef struct SpiceVmcState SpiceVmcState;
|
||||||
|
typedef struct SpiceVmcStateClass SpiceVmcStateClass;
|
||||||
|
|
||||||
|
struct SpiceVmcState
|
||||||
|
{
|
||||||
|
RedChannel parent;
|
||||||
|
|
||||||
|
RedChannelClient *rcc;
|
||||||
|
RedCharDevice *chardev;
|
||||||
|
SpiceCharDeviceInstance *chardev_sin;
|
||||||
|
RedVmcPipeItem *pipe_item;
|
||||||
|
RedCharDeviceWriteBuffer *recv_from_client_buf;
|
||||||
|
uint8_t port_opened;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpiceVmcStateClass
|
||||||
|
{
|
||||||
|
RedChannelClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType spice_vmc_state_get_type(void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(SpiceVmcState, spice_vmc_state, RED_TYPE_CHANNEL)
|
||||||
|
|
||||||
|
|
||||||
|
#define SPICE_TYPE_VMC_STATE_USBREDIR spice_vmc_state_usbredir_get_type()
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpiceVmcState parent;
|
||||||
|
} SpiceVmcStateUsbredir;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpiceVmcStateClass parent_class;
|
||||||
|
} SpiceVmcStateUsbredirClass;
|
||||||
|
|
||||||
|
GType spice_vmc_state_usbredir_get_type(void) G_GNUC_CONST;
|
||||||
|
static void spice_vmc_state_usbredir_init(SpiceVmcStateUsbredir *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
G_DEFINE_TYPE(SpiceVmcStateUsbredir, spice_vmc_state_usbredir, SPICE_TYPE_VMC_STATE)
|
||||||
|
|
||||||
|
|
||||||
|
#define SPICE_TYPE_VMC_STATE_WEBDAV spice_vmc_state_webdav_get_type()
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpiceVmcState parent;
|
||||||
|
} SpiceVmcStateWebdav;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpiceVmcStateClass parent_class;
|
||||||
|
} SpiceVmcStateWebdavClass;
|
||||||
|
|
||||||
|
GType spice_vmc_state_webdav_get_type(void) G_GNUC_CONST;
|
||||||
|
static void spice_vmc_state_webdav_init(SpiceVmcStateWebdav *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
G_DEFINE_TYPE(SpiceVmcStateWebdav, spice_vmc_state_webdav, SPICE_TYPE_VMC_STATE)
|
||||||
|
|
||||||
|
|
||||||
|
#define SPICE_TYPE_VMC_STATE_PORT spice_vmc_state_port_get_type()
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpiceVmcState parent;
|
||||||
|
} SpiceVmcStatePort;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SpiceVmcStateClass parent_class;
|
||||||
|
} SpiceVmcStatePortClass;
|
||||||
|
|
||||||
|
GType spice_vmc_state_port_get_type(void) G_GNUC_CONST;
|
||||||
|
static void spice_vmc_state_port_init(SpiceVmcStatePort *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
G_DEFINE_TYPE(SpiceVmcStatePort, spice_vmc_state_port, SPICE_TYPE_VMC_STATE)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP0,
|
||||||
|
PROP_DEVICE_INSTANCE
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_get_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
SpiceVmcState *self = SPICE_VMC_STATE(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_DEVICE_INSTANCE:
|
||||||
|
g_value_set_pointer(value, self->chardev_sin);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_set_property(GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
SpiceVmcState *self = SPICE_VMC_STATE(object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_DEVICE_INSTANCE:
|
||||||
|
self->chardev_sin = g_value_get_pointer(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spicevmc_connect(RedChannel *channel, RedClient *client,
|
||||||
|
RedsStream *stream, int migration, int num_common_caps,
|
||||||
|
uint32_t *common_caps, int num_caps, uint32_t *caps);
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_constructed(GObject *object)
|
||||||
|
{
|
||||||
|
SpiceVmcState *self = SPICE_VMC_STATE(object);
|
||||||
|
ClientCbs client_cbs = { NULL, };
|
||||||
|
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(spice_vmc_state_parent_class)->constructed(object);
|
||||||
|
|
||||||
|
client_cbs.connect = spicevmc_connect;
|
||||||
|
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs, NULL);
|
||||||
|
|
||||||
|
#ifdef USE_LZ4
|
||||||
|
red_channel_set_cap(RED_CHANNEL(self), SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
red_channel_init_outgoing_messages_window(RED_CHANNEL(self));
|
||||||
|
|
||||||
|
self->chardev = red_char_device_spicevmc_new(self->chardev_sin, reds, self);
|
||||||
|
|
||||||
|
reds_register_channel(reds, RED_CHANNEL(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_init(SpiceVmcState *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpiceVmcState *spice_vmc_state_new(RedsState *reds, uint8_t channel_type,
|
||||||
|
SpiceCharDeviceInstance *sin)
|
||||||
|
{
|
||||||
|
GType gtype = G_TYPE_NONE;
|
||||||
|
static uint8_t id[256] = { 0, };
|
||||||
|
|
||||||
|
switch (channel_type) {
|
||||||
|
case SPICE_CHANNEL_USBREDIR:
|
||||||
|
gtype = SPICE_TYPE_VMC_STATE_USBREDIR;
|
||||||
|
break;
|
||||||
|
case SPICE_CHANNEL_WEBDAV:
|
||||||
|
gtype = SPICE_TYPE_VMC_STATE_WEBDAV;
|
||||||
|
break;
|
||||||
|
case SPICE_CHANNEL_PORT:
|
||||||
|
gtype = SPICE_TYPE_VMC_STATE_PORT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_error("Unsupported channel_type for spice_vmc_state_new(): %u", channel_type);
|
||||||
|
}
|
||||||
|
return g_object_new(gtype,
|
||||||
|
"spice-server", reds,
|
||||||
|
"core-interface", reds_get_core_interface(reds),
|
||||||
|
"channel-type", channel_type,
|
||||||
|
"id", id[channel_type]++,
|
||||||
|
"handle-acks", FALSE,
|
||||||
|
"migration-flags",
|
||||||
|
(SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER),
|
||||||
|
"device-instance", sin,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct RedPortInitPipeItem {
|
typedef struct RedPortInitPipeItem {
|
||||||
RedPipeItem base;
|
RedPipeItem base;
|
||||||
char* name;
|
char* name;
|
||||||
@ -136,7 +327,7 @@ static RedVmcPipeItem* try_compress_lz4(SpiceVmcState *state, int n, RedVmcPipeI
|
|||||||
/* n <= threshold - data will not be compressed */
|
/* n <= threshold - data will not be compressed */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!red_channel_test_remote_cap(&state->channel, SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4)) {
|
if (!red_channel_test_remote_cap(RED_CHANNEL(state), SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4)) {
|
||||||
/* Client doesn't have compression cap - data will not be compressed */
|
/* Client doesn't have compression cap - data will not be compressed */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -220,7 +411,7 @@ static void spicevmc_chardev_send_msg_to_client(RedPipeItem *msg,
|
|||||||
static SpiceVmcState *spicevmc_red_channel_client_get_state(RedChannelClient *rcc)
|
static SpiceVmcState *spicevmc_red_channel_client_get_state(RedChannelClient *rcc)
|
||||||
{
|
{
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
return SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
|
return SPICE_VMC_STATE(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spicevmc_port_send_init(RedChannelClient *rcc)
|
static void spicevmc_port_send_init(RedChannelClient *rcc)
|
||||||
@ -267,8 +458,10 @@ static int spicevmc_red_channel_client_config_socket(RedChannelClient *rcc)
|
|||||||
int delay_val = 1;
|
int delay_val = 1;
|
||||||
RedsStream *stream = red_channel_client_get_stream(rcc);
|
RedsStream *stream = red_channel_client_get_stream(rcc);
|
||||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
if (channel->type == SPICE_CHANNEL_USBREDIR) {
|
g_object_get(channel, "channel-type", &type, NULL);
|
||||||
|
if (type == SPICE_CHANNEL_USBREDIR) {
|
||||||
if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
|
if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
|
||||||
&delay_val, sizeof(delay_val)) != 0) {
|
&delay_val, sizeof(delay_val)) != 0) {
|
||||||
if (errno != ENOTSUP && errno != ENOPROTOOPT) {
|
if (errno != ENOTSUP && errno != ENOPROTOOPT) {
|
||||||
@ -556,6 +749,61 @@ static void spicevmc_red_channel_send_item(RedChannelClient *rcc,
|
|||||||
red_channel_client_begin_send_message(rcc);
|
red_channel_client_begin_send_message(rcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_class_init(SpiceVmcStateClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
object_class->get_property = spice_vmc_state_get_property;
|
||||||
|
object_class->set_property = spice_vmc_state_set_property;
|
||||||
|
object_class->constructed = spice_vmc_state_constructed;
|
||||||
|
|
||||||
|
channel_class->handle_parsed = spicevmc_red_channel_client_handle_message_parsed;
|
||||||
|
|
||||||
|
channel_class->config_socket = spicevmc_red_channel_client_config_socket;
|
||||||
|
channel_class->on_disconnect = spicevmc_red_channel_client_on_disconnect;
|
||||||
|
channel_class->send_item = spicevmc_red_channel_send_item;
|
||||||
|
channel_class->alloc_recv_buf = spicevmc_red_channel_alloc_msg_rcv_buf;
|
||||||
|
channel_class->release_recv_buf = spicevmc_red_channel_release_msg_rcv_buf;
|
||||||
|
channel_class->handle_migrate_flush_mark = spicevmc_channel_client_handle_migrate_flush_mark;
|
||||||
|
channel_class->handle_migrate_data = spicevmc_channel_client_handle_migrate_data;
|
||||||
|
|
||||||
|
g_object_class_install_property(object_class,
|
||||||
|
PROP_DEVICE_INSTANCE,
|
||||||
|
g_param_spec_pointer("device-instance",
|
||||||
|
"device instance",
|
||||||
|
"Device instance for this channel",
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_usbredir_class_init(SpiceVmcStateUsbredirClass *klass)
|
||||||
|
{
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_USBREDIR, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_webdav_class_init(SpiceVmcStateWebdavClass *klass)
|
||||||
|
{
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_WEBDAV, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
spice_vmc_state_port_class_init(SpiceVmcStatePortClass *klass)
|
||||||
|
{
|
||||||
|
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
|
||||||
|
|
||||||
|
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_PORT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void spicevmc_connect(RedChannel *channel, RedClient *client,
|
static void spicevmc_connect(RedChannel *channel, RedClient *client,
|
||||||
RedsStream *stream, int migration, int num_common_caps,
|
RedsStream *stream, int migration, int num_common_caps,
|
||||||
uint32_t *common_caps, int num_caps, uint32_t *caps)
|
uint32_t *common_caps, int num_caps, uint32_t *caps)
|
||||||
@ -564,13 +812,15 @@ static void spicevmc_connect(RedChannel *channel, RedClient *client,
|
|||||||
SpiceVmcState *state;
|
SpiceVmcState *state;
|
||||||
SpiceCharDeviceInstance *sin;
|
SpiceCharDeviceInstance *sin;
|
||||||
SpiceCharDeviceInterface *sif;
|
SpiceCharDeviceInterface *sif;
|
||||||
|
uint32_t type, id;
|
||||||
|
|
||||||
state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
|
state = SPICE_VMC_STATE(channel);
|
||||||
sin = state->chardev_sin;
|
sin = state->chardev_sin;
|
||||||
|
g_object_get(channel, "channel-type", &type, "id", &id, NULL);
|
||||||
|
|
||||||
if (state->rcc) {
|
if (state->rcc) {
|
||||||
spice_printerr("channel client %d:%d (%p) already connected, refusing second connection",
|
spice_printerr("channel client %d:%d (%p) already connected, refusing second connection",
|
||||||
channel->type, channel->id, state->rcc);
|
type, id, state->rcc);
|
||||||
// TODO: notify client in advance about the in use channel using
|
// TODO: notify client in advance about the in use channel using
|
||||||
// SPICE_MSG_MAIN_CHANNEL_IN_USE (for example)
|
// SPICE_MSG_MAIN_CHANNEL_IN_USE (for example)
|
||||||
reds_stream_free(stream);
|
reds_stream_free(stream);
|
||||||
@ -606,38 +856,8 @@ RedCharDevice *spicevmc_device_connect(RedsState *reds,
|
|||||||
SpiceCharDeviceInstance *sin,
|
SpiceCharDeviceInstance *sin,
|
||||||
uint8_t channel_type)
|
uint8_t channel_type)
|
||||||
{
|
{
|
||||||
static uint8_t id[256] = { 0, };
|
SpiceVmcState *state = spice_vmc_state_new(reds, channel_type, sin);
|
||||||
SpiceVmcState *state;
|
|
||||||
ChannelCbs channel_cbs = { NULL, };
|
|
||||||
ClientCbs client_cbs = { NULL, };
|
|
||||||
|
|
||||||
channel_cbs.config_socket = spicevmc_red_channel_client_config_socket;
|
|
||||||
channel_cbs.on_disconnect = spicevmc_red_channel_client_on_disconnect;
|
|
||||||
channel_cbs.send_item = spicevmc_red_channel_send_item;
|
|
||||||
channel_cbs.alloc_recv_buf = spicevmc_red_channel_alloc_msg_rcv_buf;
|
|
||||||
channel_cbs.release_recv_buf = spicevmc_red_channel_release_msg_rcv_buf;
|
|
||||||
channel_cbs.handle_migrate_flush_mark = spicevmc_channel_client_handle_migrate_flush_mark;
|
|
||||||
channel_cbs.handle_migrate_data = spicevmc_channel_client_handle_migrate_data;
|
|
||||||
|
|
||||||
state = (SpiceVmcState*)red_channel_create_parser(sizeof(SpiceVmcState), reds,
|
|
||||||
reds_get_core_interface(reds), channel_type, id[channel_type]++,
|
|
||||||
FALSE /* handle_acks */,
|
|
||||||
spice_get_client_channel_parser(channel_type, NULL),
|
|
||||||
spicevmc_red_channel_client_handle_message_parsed,
|
|
||||||
&channel_cbs,
|
|
||||||
SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER);
|
|
||||||
red_channel_init_outgoing_messages_window(&state->channel);
|
|
||||||
|
|
||||||
client_cbs.connect = spicevmc_connect;
|
|
||||||
red_channel_register_client_cbs(&state->channel, &client_cbs, NULL);
|
|
||||||
#ifdef USE_LZ4
|
|
||||||
red_channel_set_cap(&state->channel, SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
state->chardev = red_char_device_spicevmc_new(sin, reds, state);
|
|
||||||
state->chardev_sin = sin;
|
|
||||||
|
|
||||||
reds_register_channel(reds, &state->channel);
|
|
||||||
return state->chardev;
|
return state->chardev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,15 +870,14 @@ void spicevmc_device_disconnect(RedsState *reds, SpiceCharDeviceInstance *sin)
|
|||||||
state = (SpiceVmcState *)red_char_device_opaque_get((RedCharDevice*)sin->st);
|
state = (SpiceVmcState *)red_char_device_opaque_get((RedCharDevice*)sin->st);
|
||||||
|
|
||||||
red_char_device_write_buffer_release(state->chardev, &state->recv_from_client_buf);
|
red_char_device_write_buffer_release(state->chardev, &state->recv_from_client_buf);
|
||||||
|
|
||||||
/* FIXME */
|
/* FIXME */
|
||||||
red_char_device_destroy((RedCharDevice*)sin->st);
|
red_char_device_destroy((RedCharDevice*)sin->st);
|
||||||
state->chardev = NULL;
|
state->chardev = NULL;
|
||||||
sin->st = NULL;
|
sin->st = NULL;
|
||||||
|
|
||||||
reds_unregister_channel(reds, &state->channel);
|
reds_unregister_channel(reds, RED_CHANNEL(state));
|
||||||
free(state->pipe_item);
|
free(state->pipe_item);
|
||||||
red_channel_destroy(&state->channel);
|
red_channel_destroy(RED_CHANNEL(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
SPICE_GNUC_VISIBLE void spice_server_port_event(SpiceCharDeviceInstance *sin, uint8_t event)
|
SPICE_GNUC_VISIBLE void spice_server_port_event(SpiceCharDeviceInstance *sin, uint8_t event)
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "display-channel.h"
|
#include "display-channel-private.h"
|
||||||
#include "main-channel-client.h"
|
#include "main-channel-client.h"
|
||||||
|
|
||||||
#define FPS_TEST_INTERVAL 1
|
#define FPS_TEST_INTERVAL 1
|
||||||
@ -198,7 +198,7 @@ static void update_copy_graduality(DisplayChannel *display, Drawable *drawable)
|
|||||||
SpiceBitmap *bitmap;
|
SpiceBitmap *bitmap;
|
||||||
spice_return_if_fail(drawable->red_drawable->type == QXL_DRAW_COPY);
|
spice_return_if_fail(drawable->red_drawable->type == QXL_DRAW_COPY);
|
||||||
|
|
||||||
if (display->priv->stream_video != SPICE_STREAM_VIDEO_FILTER) {
|
if (display_channel_get_stream_video(display) != SPICE_STREAM_VIDEO_FILTER) {
|
||||||
drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
|
drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user