mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-29 00:41:33 +00:00
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:
parent
1e9205a3b8
commit
fd06625ba1
@ -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();
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user