ui/vdagent: add serial capability support
The Spice agent implements a simple serial mechanism to avoid clipboard
races between client & guest. See:
045a6978d6
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									1b17f1e9f9
								
							
						
					
					
						commit
						835f69f4e6
					
				@ -102,6 +102,8 @@ struct QemuClipboardNotify {
 | 
				
			|||||||
 * @owner: clipboard owner.
 | 
					 * @owner: clipboard owner.
 | 
				
			||||||
 * @selection: clipboard selection.
 | 
					 * @selection: clipboard selection.
 | 
				
			||||||
 * @types: clipboard data array (one entry per type).
 | 
					 * @types: clipboard data array (one entry per type).
 | 
				
			||||||
 | 
					 * @has_serial: whether @serial is available.
 | 
				
			||||||
 | 
					 * @serial: the grab serial counter.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Clipboard content data and metadata.
 | 
					 * Clipboard content data and metadata.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -109,6 +111,8 @@ struct QemuClipboardInfo {
 | 
				
			|||||||
    uint32_t refcount;
 | 
					    uint32_t refcount;
 | 
				
			||||||
    QemuClipboardPeer *owner;
 | 
					    QemuClipboardPeer *owner;
 | 
				
			||||||
    QemuClipboardSelection selection;
 | 
					    QemuClipboardSelection selection;
 | 
				
			||||||
 | 
					    bool has_serial;
 | 
				
			||||||
 | 
					    uint32_t serial;
 | 
				
			||||||
    struct {
 | 
					    struct {
 | 
				
			||||||
        bool available;
 | 
					        bool available;
 | 
				
			||||||
        bool requested;
 | 
					        bool requested;
 | 
				
			||||||
 | 
				
			|||||||
@ -135,3 +135,4 @@ vdagent_recv_msg(const char *name, uint32_t size) "msg %s, size %d"
 | 
				
			|||||||
vdagent_peer_cap(const char *name) "cap %s"
 | 
					vdagent_peer_cap(const char *name) "cap %s"
 | 
				
			||||||
vdagent_cb_grab_selection(const char *name) "selection %s"
 | 
					vdagent_cb_grab_selection(const char *name) "selection %s"
 | 
				
			||||||
vdagent_cb_grab_type(const char *name) "type %s"
 | 
					vdagent_cb_grab_type(const char *name) "type %s"
 | 
				
			||||||
 | 
					vdagent_cb_serial_discard(uint32_t current, uint32_t received) "current=%u, received=%u"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										39
									
								
								ui/vdagent.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								ui/vdagent.c
									
									
									
									
									
								
							@ -59,6 +59,7 @@ struct VDAgentChardev {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* clipboard */
 | 
					    /* clipboard */
 | 
				
			||||||
    QemuClipboardPeer cbpeer;
 | 
					    QemuClipboardPeer cbpeer;
 | 
				
			||||||
 | 
					    uint32_t last_serial[QEMU_CLIPBOARD_SELECTION__COUNT];
 | 
				
			||||||
    uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT];
 | 
					    uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
typedef struct VDAgentChardev VDAgentChardev;
 | 
					typedef struct VDAgentChardev VDAgentChardev;
 | 
				
			||||||
@ -203,6 +204,9 @@ static void vdagent_send_caps(VDAgentChardev *vd)
 | 
				
			|||||||
    if (vd->clipboard) {
 | 
					    if (vd->clipboard) {
 | 
				
			||||||
        caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
 | 
					        caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
 | 
				
			||||||
        caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
 | 
					        caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
 | 
				
			||||||
 | 
					#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
 | 
				
			||||||
 | 
					        caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vdagent_send_msg(vd, msg);
 | 
					    vdagent_send_msg(vd, msg);
 | 
				
			||||||
@ -333,7 +337,8 @@ static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    g_autofree VDAgentMessage *msg =
 | 
					    g_autofree VDAgentMessage *msg =
 | 
				
			||||||
        g_malloc0(sizeof(VDAgentMessage) +
 | 
					        g_malloc0(sizeof(VDAgentMessage) +
 | 
				
			||||||
                  sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1));
 | 
					                  sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1) +
 | 
				
			||||||
 | 
					                  sizeof(uint32_t));
 | 
				
			||||||
    uint8_t *s = msg->data;
 | 
					    uint8_t *s = msg->data;
 | 
				
			||||||
    uint32_t *data = (uint32_t *)msg->data;
 | 
					    uint32_t *data = (uint32_t *)msg->data;
 | 
				
			||||||
    uint32_t q, type;
 | 
					    uint32_t q, type;
 | 
				
			||||||
@ -346,6 +351,19 @@ static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
 | 
				
			||||||
 | 
					    if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
 | 
				
			||||||
 | 
					        if (!info->has_serial) {
 | 
				
			||||||
 | 
					            /* client should win */
 | 
				
			||||||
 | 
					            info->serial = vd->last_serial[info->selection]++;
 | 
				
			||||||
 | 
					            info->has_serial = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        *data = info->serial;
 | 
				
			||||||
 | 
					        data++;
 | 
				
			||||||
 | 
					        msg->size += sizeof(uint32_t);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) {
 | 
					    for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) {
 | 
				
			||||||
        type = type_qemu_to_vdagent(q);
 | 
					        type = type_qemu_to_vdagent(q);
 | 
				
			||||||
        if (type != VD_AGENT_CLIPBOARD_NONE && info->types[q].available) {
 | 
					        if (type != VD_AGENT_CLIPBOARD_NONE && info->types[q].available) {
 | 
				
			||||||
@ -494,6 +512,24 @@ static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
 | 
					    trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
 | 
				
			||||||
    info = qemu_clipboard_info_new(&vd->cbpeer, s);
 | 
					    info = qemu_clipboard_info_new(&vd->cbpeer, s);
 | 
				
			||||||
 | 
					#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
 | 
				
			||||||
 | 
					    if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
 | 
				
			||||||
 | 
					        if (size < sizeof(uint32_t)) {
 | 
				
			||||||
 | 
					            /* this shouldn't happen! */
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        info->has_serial = true;
 | 
				
			||||||
 | 
					        info->serial = *(uint32_t *)data;
 | 
				
			||||||
 | 
					        if (info->serial < vd->last_serial[s]) {
 | 
				
			||||||
 | 
					            /* discard lower-ordering guest grab */
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vd->last_serial[s] = info->serial;
 | 
				
			||||||
 | 
					        data += sizeof(uint32_t);
 | 
				
			||||||
 | 
					        size -= sizeof(uint32_t);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    if (size > sizeof(uint32_t) * 10) {
 | 
					    if (size > sizeof(uint32_t) * 10) {
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
         * spice has 6 types as of 2021. Limiting to 10 entries
 | 
					         * spice has 6 types as of 2021. Limiting to 10 entries
 | 
				
			||||||
@ -671,6 +707,7 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
 | 
				
			|||||||
        qemu_input_handler_activate(vd->mouse_hs);
 | 
					        qemu_input_handler_activate(vd->mouse_hs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
 | 
					    if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
 | 
				
			||||||
 | 
					        memset(vd->last_serial, 0, sizeof(vd->last_serial));
 | 
				
			||||||
        vd->cbpeer.name = "vdagent";
 | 
					        vd->cbpeer.name = "vdagent";
 | 
				
			||||||
        vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
 | 
					        vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
 | 
				
			||||||
        vd->cbpeer.request = vdagent_clipboard_request;
 | 
					        vd->cbpeer.request = vdagent_clipboard_request;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user