[Spice-devel] [RFC PATCH vd_agent 3/3] Receive the graphics_device_info message
Lukáš Hrázký
lhrazky at redhat.com
Thu Nov 8 10:43:23 UTC 2018
On Thu, 2018-11-08 at 05:18 -0500, Frediano Ziglio wrote:
> >
> > The graphics_device_info message contains the device display ID
> > information (device address and device display ID). Stores the data in a
> > hash table in vdagent.
> >
> > Signed-off-by: Lukáš Hrázký <lhrazky at redhat.com>
> > ---
> > src/vdagent/vdagent.c | 69 ++++++++++++++++++++++++++++++++++++
> > src/vdagentd-proto-strings.h | 1 +
> > src/vdagentd-proto.h | 1 +
> > src/vdagentd/vdagentd.c | 16 +++++++++
> > 4 files changed, 87 insertions(+)
> >
> > diff --git a/src/vdagent/vdagent.c b/src/vdagent/vdagent.c
> > index f7c8b72..d1af57f 100644
> > --- a/src/vdagent/vdagent.c
> > +++ b/src/vdagent/vdagent.c
> > @@ -53,6 +53,7 @@ typedef struct VDAgent {
> > struct vdagent_file_xfers *xfers;
> > struct udscs_connection *conn;
> > GIOChannel *x11_channel;
> > + GHashTable *graphics_display_infos;
> >
> > GMainLoop *loop;
> > } VDAgent;
> > @@ -95,6 +96,16 @@ static GOptionEntry entries[] = {
> > { NULL }
> > };
> >
> > +typedef struct GraphicsDisplayInfo {
>
> Why this name went from GraphicsDevice to GraphicsDisplay ?
Ah, sorry, a mistake in renaming...
> > + char device_address[256];
> > + uint32_t device_display_id;
> > +} GraphicsDisplayInfo;
> > +
> > +static void graphics_display_info_destroy(gpointer gdi)
> > +{
> > + g_free(gdi);
> > +}
> > +
> > /**
> > * xfer_get_download_directory
> > *
> > @@ -159,6 +170,55 @@ static gboolean vdagent_finalize_file_xfer(VDAgent
> > *agent)
> > return TRUE;
> > }
> >
> > +static void vdagent_handle_graphics_device_info(VDAgent *agent, uint8_t
> > *data, size_t size)
> > +{
> > + VDAgentGraphicsDeviceInfos *graphics_device_infos =
> > (VDAgentGraphicsDeviceInfos *)data;
> > + VDAgentGraphicsDeviceInfo *graphics_device_info =
> > graphics_device_infos->graphics_device_infos;
> > +
> > + void *buffer_end = data + size;
> > +
> > + syslog(LOG_INFO, "Received Graphics Device Info:");
> > +
> > + for (size_t i = 0; i < graphics_device_infos->count; ++i) {
> > + if ((void*) graphics_device_info > buffer_end ||
> > + (void*) (&graphics_device_info->device_address +
> > + graphics_device_info->device_address_len) > buffer_end)
> > {
> > + syslog(LOG_ERR, "Malformed graphics_display_info message, "
> > + "extends beyond the end of the buffer");
> > + break;
> > + }
> > +
> > + syslog(LOG_INFO, " channel_id: %u monitor_id: %u device_address:
> > %s, "
> > + "device_display_id: %u",
> > + graphics_device_info->channel_id,
> > + graphics_device_info->monitor_id,
> > + graphics_device_info->device_address,
> > + graphics_device_info->device_display_id);
> > +
> > + GraphicsDisplayInfo *value = g_malloc(sizeof(GraphicsDisplayInfo));
>
> You can use g_new.
>
> > +
> > + size_t device_address_len =
> > graphics_device_info->device_address_len;
> > + if (device_address_len > sizeof(value->device_address)) {
> > + syslog(LOG_ERR, "Received a device address longer than %lu, "
> > + "will be truncated!", device_address_len);
> > + device_address_len = sizeof(value->device_address);
> > + }
> > +
> > + strncpy(value->device_address,
> > + (char*) graphics_device_info->device_address,
> > + device_address_len);
> > + value->device_address[device_address_len] = '\0'; // make sure the
> > string is terminated
>
> Can overflow if device_address_len == sizeof(value->device_address), will
> overflow on the ID which probably will contain a 0 inside so not a big deal
> but still overflow. Better to write the above condition as:
>
> if (device_address_len >= sizeof(value->device_address)) {
> syslog(LOG_ERR, "Received a device address longer than %lu, "
> "will be truncated!", device_address_len);
> device_address_len = sizeof(value->device_address) - 1;
> }
Good catch!
> > + value->device_display_id = graphics_device_info->device_display_id;
> > +
> > + g_hash_table_insert(agent->graphics_display_infos,
> > + GUINT_TO_POINTER(graphics_device_info->channel_id +
> > graphics_device_info->monitor_id),
>
> Still this ugly formula? Surely channel_id is limited to 8 bit as a protocol
> limitation, I would go with
>
> graphics_device_info->channel_id + (graphics_device_info->monitor_id << 8)
>
> Or use g_int64_equal/g_int64_hash instead and
>
> graphics_device_info->channel_id + (graphics_device_info->monitor_id << 32)
Can't do this. The reason I'm using the formula is because it still is
at the other end. This is what the client sends in monitors_config and
mouse_position and those IDs will be used to access the hash table.
But the good thing is if we ever fix the ugly display_id, the graphics
device info from this patch can just be stored by a different key. For
now, have to use this.
> > + value);
> > +
> > + graphics_device_info = (VDAgentGraphicsDeviceInfo*) ((char*)
> > graphics_device_info +
> > + sizeof(VDAgentGraphicsDeviceInfo) +
> > graphics_device_info->device_address_len);
>
> OT: this formula is repeated multiple times, maybe adding a macro would
> help?
The somewhat ugly pointer arithmetics? It's used once on the server and
once in the vdagent, so can't share the code, but it's not so bad?
> > + }
> > +}
> > +
> > static void vdagent_quit_loop(VDAgent *agent)
> > {
> > /* other GMainLoop(s) might be running, quit them before agent->loop */
> > @@ -243,6 +303,9 @@ static void daemon_read_complete(struct udscs_connection
> > **connp,
> > ((VDAgentFileXferDataMessage
> > *)data)->id);
> > }
> > break;
> > + case VDAGENTD_GRAPHICS_DEVICE_INFO:
> > + vdagent_handle_graphics_device_info(agent, data, header->size);
> > + break;
> > case VDAGENTD_CLIENT_DISCONNECTED:
> > vdagent_clipboards_release_all(agent->clipboards);
> > if (vdagent_finalize_file_xfer(agent)) {
> > @@ -345,6 +408,11 @@ static VDAgent *vdagent_new(void)
> > g_unix_signal_add(SIGHUP, vdagent_signal_handler, agent);
> > g_unix_signal_add(SIGTERM, vdagent_signal_handler, agent);
> >
> > + agent->graphics_display_infos = g_hash_table_new_full(&g_direct_hash,
> > + &g_direct_equal,
> > + NULL,
> > +
> > &graphics_display_info_destroy);
>
> Why "&" before functions? This seems not coherent with current code.
Right, I'll remove them.
> > +
> > return agent;
> > }
> >
> > @@ -359,6 +427,7 @@ static void vdagent_destroy(VDAgent *agent)
> >
> > g_clear_pointer(&agent->x11_channel, g_io_channel_unref);
> > g_clear_pointer(&agent->loop, g_main_loop_unref);
> > + g_hash_table_destroy(agent->graphics_display_infos);
> > g_free(agent);
> > }
> >
> > diff --git a/src/vdagentd-proto-strings.h b/src/vdagentd-proto-strings.h
> > index 6e7bcee..7e03f46 100644
> > --- a/src/vdagentd-proto-strings.h
> > +++ b/src/vdagentd-proto-strings.h
> > @@ -36,6 +36,7 @@ static const char * const vdagentd_messages[] = {
> > "file xfer data",
> > "file xfer disable",
> > "client disconnected",
> > + "graphics device info",
> > };
> >
> > #endif
> > diff --git a/src/vdagentd-proto.h b/src/vdagentd-proto.h
> > index f72a890..243a9c6 100644
> > --- a/src/vdagentd-proto.h
> > +++ b/src/vdagentd-proto.h
> > @@ -44,6 +44,7 @@ enum {
> > VDAGENTD_FILE_XFER_DATA,
> > VDAGENTD_FILE_XFER_DISABLE,
> > VDAGENTD_CLIENT_DISCONNECTED, /* daemon -> client */
> > + VDAGENTD_GRAPHICS_DEVICE_INFO, /* daemon -> client */
> > VDAGENTD_NO_MESSAGES /* Must always be last */
> > };
> >
> > diff --git a/src/vdagentd/vdagentd.c b/src/vdagentd/vdagentd.c
> > index 99683da..7c37358 100644
> > --- a/src/vdagentd/vdagentd.c
> > +++ b/src/vdagentd/vdagentd.c
> > @@ -375,6 +375,16 @@ static void do_client_file_xfer(struct
> > vdagent_virtio_port *vport,
> > udscs_write(conn, msg_type, 0, 0, data, message_header->size);
> > }
> >
> > +static void forward_data_to_session_agent(uint32_t type, uint8_t *data,
> > size_t size)
> > +{
> > + if (active_session_conn == NULL) {
> > + syslog(LOG_DEBUG, "No active session, can't forward message (type
> > %u)", type);
>
> Won't be need to cache this value and forward also to new sessions?
> The new session should know the current values.
Each new session agent should get the data sent again. At least that's
how I understand it and how it worked for me when testing a simple
login session -> user session case...
Thanks,
Lukas
> > + return;
> > + }
> > +
> > + udscs_write(active_session_conn, type, 0, 0, data, size);
> > +}
> > +
> > static gsize vdagent_message_min_size[] =
> > {
> > -1, /* Does not exist */
> > @@ -393,6 +403,7 @@ static gsize vdagent_message_min_size[] =
> > 0, /* VD_AGENT_CLIENT_DISCONNECTED */
> > sizeof(VDAgentMaxClipboard), /* VD_AGENT_MAX_CLIPBOARD */
> > sizeof(VDAgentAudioVolumeSync), /* VD_AGENT_AUDIO_VOLUME_SYNC */
> > + sizeof(VDAgentGraphicsDeviceInfo), /* VD_AGENT_GRAPHICS_DEVICE_INFO */
> > };
> >
> > static void vdagent_message_clipboard_from_le(VDAgentMessage
> > *message_header,
> > @@ -477,6 +488,7 @@ static gboolean vdagent_message_check_size(const
> > VDAgentMessage *message_header)
> > case VD_AGENT_CLIPBOARD_GRAB:
> > case VD_AGENT_AUDIO_VOLUME_SYNC:
> > case VD_AGENT_ANNOUNCE_CAPABILITIES:
> > + case VD_AGENT_GRAPHICS_DEVICE_INFO:
> > if (message_header->size < min_size) {
> > syslog(LOG_ERR, "read: invalid message size: %u for message
> > type: %u",
> > message_header->size, message_header->type);
> > @@ -550,6 +562,10 @@ static int virtio_port_read_complete(
> > syslog(LOG_DEBUG, "Set max clipboard: %d", max_clipboard);
> > break;
> > }
> > + case VD_AGENT_GRAPHICS_DEVICE_INFO: {
> > + forward_data_to_session_agent(VDAGENTD_GRAPHICS_DEVICE_INFO, data,
> > message_header->size);
> > + break;
> > + }
> > case VD_AGENT_AUDIO_VOLUME_SYNC: {
> > VDAgentAudioVolumeSync *vdata = (VDAgentAudioVolumeSync *)data;
> > virtio_msg_uint16_from_le((uint8_t *)vdata, message_header->size,
>
> Frediano
More information about the Spice-devel
mailing list