red-stream-device: Better encapsulation

Remove all members public, set correct access and create
missing methods.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
Frediano Ziglio 2020-03-15 07:02:42 +00:00 committed by Frediano Ziglio
parent 1e9205a3b8
commit fd06625ba1
3 changed files with 190 additions and 183 deletions

View File

@ -27,19 +27,10 @@
static void char_device_set_state(RedCharDevice *char_dev, int state);
typedef bool StreamMsgHandler(StreamDevice *dev, SpiceCharDeviceInstance *sin)
SPICE_GNUC_WARN_UNUSED_RESULT;
static StreamMsgHandler handle_msg_format, handle_msg_device_display_info, handle_msg_data,
handle_msg_cursor_set, handle_msg_cursor_move, handle_msg_capabilities;
static bool handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin,
const char *error_msg) SPICE_GNUC_WARN_UNUSED_RESULT;
RECORDER(stream_device_data, 32, "Stream device data packet");
static void
close_timer_func(StreamDevice *dev)
void
StreamDevice::close_timer_func(StreamDevice *dev)
{
if (dev->opened && dev->has_error) {
char_device_set_state(dev, 0);
@ -55,8 +46,8 @@ fill_dev_hdr(StreamDevHeader *hdr, StreamMsgType msg_type, uint32_t msg_size)
hdr->size = GUINT32_TO_LE(msg_size);
}
static bool
stream_device_partial_read(StreamDevice *dev, SpiceCharDeviceInstance *sin)
bool
StreamDevice::partial_read(SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif;
int n;
@ -67,7 +58,7 @@ stream_device_partial_read(StreamDevice *dev, SpiceCharDeviceInstance *sin)
// in order to get in sync every time we open the device we need to discard data here.
// Qemu keeps a buffer of data which is used only during spice_server_char_device_wakeup
// from Qemu
if (G_UNLIKELY(dev->has_error)) {
if (G_UNLIKELY(has_error)) {
uint8_t buf[16 * 1024];
while (sif->read(sin, buf, sizeof(buf)) > 0) {
continue;
@ -78,87 +69,87 @@ stream_device_partial_read(StreamDevice *dev, SpiceCharDeviceInstance *sin)
// As calling sif->state here can cause a crash, schedule
// a timer and do the call in it. Remove this code when
// we are sure all Qemu versions have been patched.
RedsState *reds = dev->get_server();
if (!dev->close_timer) {
dev->close_timer = reds_core_timer_add(reds, close_timer_func, dev);
RedsState *reds = get_server();
if (!close_timer) {
close_timer = reds_core_timer_add(reds, close_timer_func, this);
}
red_timer_start(dev->close_timer, 0);
red_timer_start(close_timer, 0);
return false;
}
if (dev->flow_stopped || !dev->stream_channel) {
if (flow_stopped || !stream_channel) {
return false;
}
/* read header */
while (dev->hdr_pos < sizeof(dev->hdr)) {
n = sif->read(sin, (uint8_t *) &dev->hdr + dev->hdr_pos, sizeof(dev->hdr) - dev->hdr_pos);
while (hdr_pos < sizeof(hdr)) {
n = sif->read(sin, (uint8_t *) &hdr + hdr_pos, sizeof(hdr) - hdr_pos);
if (n <= 0) {
return false;
}
dev->hdr_pos += n;
if (dev->hdr_pos >= sizeof(dev->hdr)) {
dev->hdr.type = GUINT16_FROM_LE(dev->hdr.type);
dev->hdr.size = GUINT32_FROM_LE(dev->hdr.size);
dev->msg_pos = 0;
hdr_pos += n;
if (hdr_pos >= sizeof(hdr)) {
hdr.type = GUINT16_FROM_LE(hdr.type);
hdr.size = GUINT32_FROM_LE(hdr.size);
msg_pos = 0;
}
}
switch ((StreamMsgType) dev->hdr.type) {
switch ((StreamMsgType) hdr.type) {
case STREAM_TYPE_FORMAT:
if (dev->hdr.size != sizeof(StreamMsgFormat)) {
handled = handle_msg_invalid(dev, sin, "Wrong size for StreamMsgFormat");
if (hdr.size != sizeof(StreamMsgFormat)) {
handled = handle_msg_invalid(sin, "Wrong size for StreamMsgFormat");
} else {
handled = handle_msg_format(dev, sin);
handled = handle_msg_format(sin);
}
break;
case STREAM_TYPE_DEVICE_DISPLAY_INFO:
if (dev->hdr.size > sizeof(StreamMsgDeviceDisplayInfo) + MAX_DEVICE_ADDRESS_LEN) {
handled = handle_msg_invalid(dev, sin, "StreamMsgDeviceDisplayInfo too large");
if (hdr.size > sizeof(StreamMsgDeviceDisplayInfo) + MAX_DEVICE_ADDRESS_LEN) {
handled = handle_msg_invalid(sin, "StreamMsgDeviceDisplayInfo too large");
} else {
handled = handle_msg_device_display_info(dev, sin);
handled = handle_msg_device_display_info(sin);
}
break;
case STREAM_TYPE_DATA:
if (dev->hdr.size > 32*1024*1024) {
handled = handle_msg_invalid(dev, sin, "STREAM_DATA too large");
if (hdr.size > 32*1024*1024) {
handled = handle_msg_invalid(sin, "STREAM_DATA too large");
} else {
handled = handle_msg_data(dev, sin);
handled = handle_msg_data(sin);
}
break;
case STREAM_TYPE_CURSOR_SET:
handled = handle_msg_cursor_set(dev, sin);
handled = handle_msg_cursor_set(sin);
break;
case STREAM_TYPE_CURSOR_MOVE:
if (dev->hdr.size != sizeof(StreamMsgCursorMove)) {
handled = handle_msg_invalid(dev, sin, "Wrong size for StreamMsgCursorMove");
if (hdr.size != sizeof(StreamMsgCursorMove)) {
handled = handle_msg_invalid(sin, "Wrong size for StreamMsgCursorMove");
} else {
handled = handle_msg_cursor_move(dev, sin);
handled = handle_msg_cursor_move(sin);
}
break;
case STREAM_TYPE_CAPABILITIES:
handled = handle_msg_capabilities(dev, sin);
handled = handle_msg_capabilities(sin);
break;
default:
handled = handle_msg_invalid(dev, sin, "Invalid message type");
handled = handle_msg_invalid(sin, "Invalid message type");
break;
}
/* current message has been handled, so reset state and get ready to parse
* the next message */
if (handled) {
dev->hdr_pos = 0;
hdr_pos = 0;
// Reallocate message buffer to the minimum.
// Currently the only message that requires resizing is the cursor shape,
// which is not expected to be sent so often.
if (dev->msg_len > sizeof(*dev->msg)) {
dev->msg = (StreamDevice::AllMessages*) g_realloc(dev->msg, sizeof(*dev->msg));
dev->msg_len = sizeof(*dev->msg);
if (msg_len > sizeof(*msg)) {
msg = (StreamDevice::AllMessages*) g_realloc(msg, sizeof(*msg));
msg_len = sizeof(*msg);
}
}
if (handled || dev->has_error) {
if (handled || has_error) {
// Qemu put the device on blocking state if we don't read all data
// so schedule another read.
// We arrive here if we processed that entire message or we
@ -172,18 +163,18 @@ stream_device_partial_read(StreamDevice *dev, SpiceCharDeviceInstance *sin)
RedPipeItem* StreamDevice::read_one_msg_from_device(SpiceCharDeviceInstance *sin)
{
while (stream_device_partial_read(this, sin)) {
while (partial_read(sin)) {
continue;
}
return NULL;
}
static bool
handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin, const char *error_msg)
bool
StreamDevice::handle_msg_invalid(SpiceCharDeviceInstance *sin, const char *error_msg)
{
static const char default_error_msg[] = "Protocol error";
spice_extra_assert(dev->hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(hdr_pos >= sizeof(StreamDevHeader));
if (!error_msg) {
error_msg = default_error_msg;
@ -194,9 +185,8 @@ handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin, const char *
int msg_size = sizeof(StreamMsgNotifyError) + strlen(error_msg) + 1;
int total_size = sizeof(StreamDevHeader) + msg_size;
RedCharDevice *char_dev = dev;
RedCharDeviceWriteBuffer *buf =
char_dev->write_buffer_get_server(total_size, false);
write_buffer_get_server(total_size, false);
buf->buf_used = total_size;
StreamDevHeader *const hdr = (StreamDevHeader *)buf->buf;
@ -206,68 +196,68 @@ handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin, const char *
error->error_code = GUINT32_TO_LE(0);
strcpy((char *) error->msg, error_msg);
char_dev->write_buffer_add(buf);
write_buffer_add(buf);
dev->has_error = true;
has_error = true;
return false;
}
static bool
handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin)
bool
StreamDevice::handle_msg_format(SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
spice_extra_assert(dev->hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(dev->hdr.type == STREAM_TYPE_FORMAT);
spice_extra_assert(hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(hdr.type == STREAM_TYPE_FORMAT);
int n = sif->read(sin, dev->msg->buf + dev->msg_pos, sizeof(StreamMsgFormat) - dev->msg_pos);
int n = sif->read(sin, msg->buf + msg_pos, sizeof(StreamMsgFormat) - msg_pos);
if (n < 0) {
return handle_msg_invalid(dev, sin, NULL);
return handle_msg_invalid(sin, NULL);
}
dev->msg_pos += n;
msg_pos += n;
if (dev->msg_pos < sizeof(StreamMsgFormat)) {
if (msg_pos < sizeof(StreamMsgFormat)) {
return false;
}
dev->msg->format.width = GUINT32_FROM_LE(dev->msg->format.width);
dev->msg->format.height = GUINT32_FROM_LE(dev->msg->format.height);
dev->stream_channel->change_format(&dev->msg->format);
msg->format.width = GUINT32_FROM_LE(msg->format.width);
msg->format.height = GUINT32_FROM_LE(msg->format.height);
stream_channel->change_format(&msg->format);
return true;
}
static bool
handle_msg_device_display_info(StreamDevice *dev, SpiceCharDeviceInstance *sin)
bool
StreamDevice::handle_msg_device_display_info(SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
spice_extra_assert(dev->hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(dev->hdr.type == STREAM_TYPE_DEVICE_DISPLAY_INFO);
spice_extra_assert(hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(hdr.type == STREAM_TYPE_DEVICE_DISPLAY_INFO);
if (dev->msg_len < dev->hdr.size) {
dev->msg = (StreamDevice::AllMessages*) g_realloc(dev->msg, dev->hdr.size);
dev->msg_len = dev->hdr.size;
if (msg_len < hdr.size) {
msg = (StreamDevice::AllMessages*) g_realloc(msg, hdr.size);
msg_len = hdr.size;
}
/* read from device */
ssize_t n = sif->read(sin, dev->msg->buf + dev->msg_pos, dev->hdr.size - dev->msg_pos);
ssize_t n = sif->read(sin, msg->buf + msg_pos, hdr.size - msg_pos);
if (n <= 0) {
return dev->msg_pos == dev->hdr.size;
return msg_pos == hdr.size;
}
dev->msg_pos += n;
if (dev->msg_pos != dev->hdr.size) { /* some bytes are still missing */
msg_pos += n;
if (msg_pos != hdr.size) { /* some bytes are still missing */
return false;
}
StreamMsgDeviceDisplayInfo *display_info_msg = &dev->msg->device_display_info;
StreamMsgDeviceDisplayInfo *display_info_msg = &msg->device_display_info;
size_t device_address_len = GUINT32_FROM_LE(display_info_msg->device_address_len);
if (device_address_len > MAX_DEVICE_ADDRESS_LEN) {
g_warning("Received a device address longer than %u (%zu), "
"will be truncated!", MAX_DEVICE_ADDRESS_LEN, device_address_len);
device_address_len = sizeof(dev->device_display_info.device_address);
device_address_len = sizeof(device_display_info.device_address);
}
if (device_address_len == 0) {
@ -275,104 +265,104 @@ handle_msg_device_display_info(StreamDevice *dev, SpiceCharDeviceInstance *sin)
return true;
}
if (display_info_msg->device_address + device_address_len > (uint8_t*) dev->msg + dev->hdr.size) {
if (display_info_msg->device_address + device_address_len > (uint8_t*) msg + hdr.size) {
g_warning("Malformed DeviceDisplayInfo message, device_address length (%zu) "
"goes beyond the end of the message, ignoring.", device_address_len);
return true;
}
memcpy(dev->device_display_info.device_address,
memcpy(device_display_info.device_address,
(char*) display_info_msg->device_address,
device_address_len);
// make sure the string is terminated
dev->device_display_info.device_address[device_address_len - 1] = '\0';
device_display_info.device_address[device_address_len - 1] = '\0';
dev->device_display_info.stream_id = GUINT32_FROM_LE(display_info_msg->stream_id);
dev->device_display_info.device_display_id = GUINT32_FROM_LE(display_info_msg->device_display_id);
device_display_info.stream_id = GUINT32_FROM_LE(display_info_msg->stream_id);
device_display_info.device_display_id = GUINT32_FROM_LE(display_info_msg->device_display_id);
g_debug("Received DeviceDisplayInfo from the streaming agent: stream_id %u, "
"device_address %s, device_display_id %u",
dev->device_display_info.stream_id,
dev->device_display_info.device_address,
dev->device_display_info.device_display_id);
device_display_info.stream_id,
device_display_info.device_address,
device_display_info.device_display_id);
reds_send_device_display_info(dev->get_server());
reds_send_device_display_info(get_server());
return true;
}
static bool
handle_msg_capabilities(StreamDevice *dev, SpiceCharDeviceInstance *sin)
bool
StreamDevice::handle_msg_capabilities(SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
spice_extra_assert(dev->hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(dev->hdr.type == STREAM_TYPE_CAPABILITIES);
spice_extra_assert(hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(hdr.type == STREAM_TYPE_CAPABILITIES);
if (dev->hdr.size > STREAM_MSG_CAPABILITIES_MAX_BYTES) {
return handle_msg_invalid(dev, sin, "Wrong size for StreamMsgCapabilities");
if (hdr.size > STREAM_MSG_CAPABILITIES_MAX_BYTES) {
return handle_msg_invalid(sin, "Wrong size for StreamMsgCapabilities");
}
int n = sif->read(sin, dev->msg->buf + dev->msg_pos, dev->hdr.size - dev->msg_pos);
int n = sif->read(sin, msg->buf + msg_pos, hdr.size - msg_pos);
if (n < 0) {
return handle_msg_invalid(dev, sin, NULL);
return handle_msg_invalid(sin, NULL);
}
dev->msg_pos += n;
msg_pos += n;
if (dev->msg_pos < dev->hdr.size) {
if (msg_pos < hdr.size) {
return false;
}
// copy only capabilities we know about
memset(dev->guest_capabilities, 0, sizeof(dev->guest_capabilities));
memcpy(dev->guest_capabilities, dev->msg->capabilities.capabilities,
MIN(sizeof(dev->guest_capabilities), dev->hdr.size));
memset(guest_capabilities, 0, sizeof(guest_capabilities));
memcpy(guest_capabilities, msg->capabilities.capabilities,
MIN(sizeof(guest_capabilities), hdr.size));
return true;
}
static bool
handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
bool
StreamDevice::handle_msg_data(SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
int n;
spice_extra_assert(dev->hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(dev->hdr.type == STREAM_TYPE_DATA);
spice_extra_assert(hdr_pos >= sizeof(StreamDevHeader));
spice_extra_assert(hdr.type == STREAM_TYPE_DATA);
/* make sure we have a large enough buffer for the whole frame */
/* ---
* TODO: Now that we copy partial data into the buffer, for each frame
* the buffer is allocated and freed (look for g_realloc in
* stream_device_partial_read).
* partial_read).
* Probably better to just keep the larger buffer.
*/
if (dev->msg_pos == 0) {
dev->frame_mmtime = reds_get_mm_time();
if (msg_pos == 0) {
frame_mmtime = reds_get_mm_time();
record(stream_device_data, "Stream data packet size %u mm_time %u",
dev->hdr.size, dev->frame_mmtime);
if (dev->msg_len < dev->hdr.size) {
g_free(dev->msg);
dev->msg = (StreamDevice::AllMessages*) g_malloc(dev->hdr.size);
dev->msg_len = dev->hdr.size;
hdr.size, frame_mmtime);
if (msg_len < hdr.size) {
g_free(msg);
msg = (StreamDevice::AllMessages*) g_malloc(hdr.size);
msg_len = hdr.size;
}
}
/* read from device */
n = sif->read(sin, dev->msg->buf + dev->msg_pos, dev->hdr.size - dev->msg_pos);
n = sif->read(sin, msg->buf + msg_pos, hdr.size - msg_pos);
if (n <= 0) {
return dev->msg_pos == dev->hdr.size;
return msg_pos == hdr.size;
}
dev->msg_pos += n;
if (dev->msg_pos != dev->hdr.size) { /* some bytes are still missing */
msg_pos += n;
if (msg_pos != hdr.size) { /* some bytes are still missing */
return false;
}
/* The whole frame was read from the device, send it */
dev->stream_channel->send_data(dev->msg->buf, dev->hdr.size, dev->frame_mmtime);
stream_channel->send_data(msg->buf, hdr.size, frame_mmtime);
return true;
}
@ -444,8 +434,8 @@ stream_msg_cursor_set_to_cursor_cmd(const StreamMsgCursorSet *msg, size_t msg_si
return cmd;
}
static bool
handle_msg_cursor_set(StreamDevice *dev, SpiceCharDeviceInstance *sin)
bool
StreamDevice::handle_msg_cursor_set(SpiceCharDeviceInstance *sin)
{
// Calculate the maximum size required to send the pixel data for a cursor that is the
// maximum size using the format that requires the largest number of bits per pixel
@ -457,50 +447,50 @@ handle_msg_cursor_set(StreamDevice *dev, SpiceCharDeviceInstance *sin)
SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
if (dev->hdr.size < sizeof(StreamMsgCursorSet) || dev->hdr.size > max_cursor_set_size) {
if (hdr.size < sizeof(StreamMsgCursorSet) || hdr.size > max_cursor_set_size) {
// we could skip the message but on the other hand the guest
// is buggy in any case
return handle_msg_invalid(dev, sin, "Cursor size is invalid");
return handle_msg_invalid(sin, "Cursor size is invalid");
}
// read part of the message till we get all
if (dev->msg_len < dev->hdr.size) {
dev->msg = (StreamDevice::AllMessages*) g_realloc(dev->msg, dev->hdr.size);
dev->msg_len = dev->hdr.size;
if (msg_len < hdr.size) {
msg = (StreamDevice::AllMessages*) g_realloc(msg, hdr.size);
msg_len = hdr.size;
}
int n = sif->read(sin, dev->msg->buf + dev->msg_pos, dev->hdr.size - dev->msg_pos);
int n = sif->read(sin, msg->buf + msg_pos, hdr.size - msg_pos);
if (n <= 0) {
return false;
}
dev->msg_pos += n;
if (dev->msg_pos != dev->hdr.size) {
msg_pos += n;
if (msg_pos != hdr.size) {
return false;
}
// transform the message to a cursor command and process it
RedCursorCmd *cmd = stream_msg_cursor_set_to_cursor_cmd(&dev->msg->cursor_set, dev->msg_pos);
RedCursorCmd *cmd = stream_msg_cursor_set_to_cursor_cmd(&msg->cursor_set, msg_pos);
if (!cmd) {
return handle_msg_invalid(dev, sin, NULL);
return handle_msg_invalid(sin, NULL);
}
cursor_channel_process_cmd(dev->cursor_channel.get(), cmd);
cursor_channel_process_cmd(cursor_channel.get(), cmd);
return true;
}
static bool
handle_msg_cursor_move(StreamDevice *dev, SpiceCharDeviceInstance *sin)
bool
StreamDevice::handle_msg_cursor_move(SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
int n = sif->read(sin, dev->msg->buf + dev->msg_pos, dev->hdr.size - dev->msg_pos);
int n = sif->read(sin, msg->buf + msg_pos, hdr.size - msg_pos);
if (n <= 0) {
return false;
}
dev->msg_pos += n;
if (dev->msg_pos != dev->hdr.size) {
msg_pos += n;
if (msg_pos != hdr.size) {
return false;
}
StreamMsgCursorMove *move = &dev->msg->cursor_move;
StreamMsgCursorMove *move = &msg->cursor_move;
move->x = GINT32_FROM_LE(move->x);
move->y = GINT32_FROM_LE(move->y);
@ -509,7 +499,7 @@ handle_msg_cursor_move(StreamDevice *dev, SpiceCharDeviceInstance *sin)
cmd->u.position.x = move->x;
cmd->u.position.y = move->y;
cursor_channel_process_cmd(dev->cursor_channel.get(), cmd);
cursor_channel_process_cmd(cursor_channel.get(), cmd);
return true;
}
@ -518,8 +508,8 @@ void StreamDevice::remove_client(RedCharDeviceClientOpaque *client)
{
}
static void
stream_device_stream_start(void *opaque, StreamMsgStartStop *start,
void
StreamDevice::stream_start(void *opaque, StreamMsgStartStop *start,
StreamChannel *stream_channel G_GNUC_UNUSED)
{
StreamDevice *dev = (StreamDevice *) opaque;
@ -543,8 +533,8 @@ stream_device_stream_start(void *opaque, StreamMsgStartStop *start,
dev->write_buffer_add(buf);
}
static void
stream_device_stream_queue_stat(void *opaque, const StreamQueueStat *stats G_GNUC_UNUSED,
void
StreamDevice::stream_queue_stat(void *opaque, const StreamQueueStat *stats G_GNUC_UNUSED,
StreamChannel *stream_channel G_GNUC_UNUSED)
{
StreamDevice *dev = (StreamDevice *) opaque;
@ -609,33 +599,30 @@ StreamDevice::~StreamDevice()
}
void
stream_device_create_channel(StreamDevice *dev)
StreamDevice::create_channel()
{
if (dev->stream_channel) {
if (stream_channel) {
return;
}
SpiceServer* reds = dev->get_server();
SpiceServer* reds = get_server();
SpiceCoreInterfaceInternal* core = reds_get_core_interface(reds);
int id = reds_get_free_channel_id(reds, SPICE_CHANNEL_DISPLAY);
g_return_if_fail(id >= 0);
auto stream_channel = stream_channel_new(reds, id);
auto cursor_channel = cursor_channel_new(reds, id, core, NULL);
stream_channel = stream_channel_new(reds, id);
cursor_channel = cursor_channel_new(reds, id, core, NULL);
dev->stream_channel = stream_channel;
dev->cursor_channel = cursor_channel;
stream_channel->register_start_cb(stream_device_stream_start, dev);
stream_channel->register_queue_stat_cb(stream_device_stream_queue_stat, dev);
stream_channel->register_start_cb(stream_start, this);
stream_channel->register_queue_stat_cb(stream_queue_stat, this);
}
static void
reset_channels(StreamDevice *dev)
void
StreamDevice::reset_channels()
{
if (dev->stream_channel) {
dev->stream_channel->reset();
if (stream_channel) {
stream_channel->reset();
}
}
@ -681,7 +668,7 @@ StreamDevice::port_event(uint8_t event)
// reset device and channel on close/open
opened = (event == SPICE_PORT_EVENT_OPENED);
if (opened) {
stream_device_create_channel(this);
create_channel();
send_capabilities(this);
}
@ -690,23 +677,23 @@ StreamDevice::port_event(uint8_t event)
has_error = false;
flow_stopped = false;
reset();
reset_channels(this);
reset_channels();
// enable the device again. We re-enable it on close as otherwise we don't want to get a
// failure when we try to re-open the device as would happen if we keep it disabled
char_device_set_state(this, 1);
}
const StreamDeviceDisplayInfo *stream_device_get_device_display_info(StreamDevice *dev)
const StreamDeviceDisplayInfo *StreamDevice::get_device_display_info()
{
return &dev->device_display_info;
return &device_display_info;
}
int32_t stream_device_get_stream_channel_id(StreamDevice *dev)
int32_t StreamDevice::get_stream_channel_id()
{
if (!dev->stream_channel) {
if (!stream_channel) {
return -1;
}
return dev->stream_channel->id();
return stream_channel->id();
}

View File

@ -34,35 +34,39 @@ struct StreamDevice;
// forward declarations
struct StreamChannel;
struct CursorChannel;
struct StreamQueueStat;
typedef struct StreamDeviceDisplayInfo {
struct StreamDeviceDisplayInfo {
uint32_t stream_id;
char device_address[MAX_DEVICE_ADDRESS_LEN];
uint32_t device_display_id;
} StreamDeviceDisplayInfo;
};
red::shared_ptr<StreamDevice> stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin);
/* Create channel for the streaming device.
* If the channel already exists the function does nothing.
*/
void stream_device_create_channel(StreamDevice *dev);
const StreamDeviceDisplayInfo *stream_device_get_device_display_info(StreamDevice *dev);
/**
* Returns -1 if the StreamDevice doesn't have a channel yet.
*/
int32_t stream_device_get_stream_channel_id(StreamDevice *dev);
#define MAX_GUEST_CAPABILITIES_BYTES ((STREAM_CAP_END+7)/8)
struct StreamDevice: public RedCharDevice
class StreamDevice final: public RedCharDevice
{
// TODO access
public:
StreamDevice(RedsState *reds, SpiceCharDeviceInstance *sin);
/* Create channel for the streaming device.
* If the channel already exists the function does nothing.
*/
void create_channel();
/**
* Returns -1 if the StreamDevice doesn't have a channel yet.
*/
int32_t get_stream_channel_id();
const StreamDeviceDisplayInfo *get_device_display_info();
protected:
~StreamDevice();
private:
StreamDevHeader hdr;
uint8_t hdr_pos;
union AllMessages {
@ -84,10 +88,26 @@ struct StreamDevice: public RedCharDevice
SpiceTimer *close_timer;
uint32_t frame_mmtime;
StreamDeviceDisplayInfo device_display_info;
protected:
private:
virtual RedPipeItem* read_one_msg_from_device(SpiceCharDeviceInstance *sin) override;
virtual void remove_client(RedCharDeviceClientOpaque *client) override;
virtual void port_event(uint8_t event) override;
bool partial_read(SpiceCharDeviceInstance *sin);
bool handle_msg_invalid(SpiceCharDeviceInstance *sin, const char *error_msg) SPICE_GNUC_WARN_UNUSED_RESULT;
bool handle_msg_capabilities(SpiceCharDeviceInstance *sin) SPICE_GNUC_WARN_UNUSED_RESULT;
bool handle_msg_format(SpiceCharDeviceInstance *sin) SPICE_GNUC_WARN_UNUSED_RESULT;
bool handle_msg_cursor_move(SpiceCharDeviceInstance *sin) SPICE_GNUC_WARN_UNUSED_RESULT;
bool handle_msg_cursor_set(SpiceCharDeviceInstance *sin) SPICE_GNUC_WARN_UNUSED_RESULT;
bool handle_msg_data(SpiceCharDeviceInstance *sin) SPICE_GNUC_WARN_UNUSED_RESULT;
bool handle_msg_device_display_info(SpiceCharDeviceInstance *sin) SPICE_GNUC_WARN_UNUSED_RESULT;
void reset_channels();
static void close_timer_func(StreamDevice *dev);
static void stream_start(void *opaque, StreamMsgStartStop *start,
StreamChannel *stream_channel);
static void stream_queue_stat(void *opaque, const StreamQueueStat *stats,
StreamChannel *stream_channel);
};
#include "pop-visibility.h"

View File

@ -851,7 +851,7 @@ void reds_marshall_device_display_info(RedsState *reds, SpiceMarshaller *m)
for (auto dev: reds->char_devices) {
auto stream_dev = dynamic_cast<StreamDevice*>(dev.get());
if (stream_dev) {
const StreamDeviceDisplayInfo *info = stream_device_get_device_display_info(stream_dev);
const StreamDeviceDisplayInfo *info = stream_dev->get_device_display_info();
size_t device_address_len = strlen(info->device_address) + 1;
if (device_address_len == 1) {
@ -859,7 +859,7 @@ void reds_marshall_device_display_info(RedsState *reds, SpiceMarshaller *m)
continue;
}
int32_t channel_id = stream_device_get_stream_channel_id(stream_dev);
int32_t channel_id = stream_dev->get_stream_channel_id();
if (channel_id == -1) {
g_warning("DeviceDisplayInfo set but no stream channel exists");
continue;
@ -1771,7 +1771,7 @@ static void reds_late_initialization(RedsState *reds)
for (auto dev: reds->char_devices) {
auto stream_dev = dynamic_cast<StreamDevice*>(dev.get());
if (stream_dev) {
stream_device_create_channel(stream_dev);
stream_dev->create_channel();
}
}
reds->late_initialization_done = true;