1 #include "qemu/osdep.h"
2 #include "qapi/error.h"
3 #include "chardev/char.h"
4 #include "qemu/buffer.h"
5 #include "qemu/error-report.h"
6 #include "qemu/option.h"
7 #include "qemu/units.h"
8 #include "hw/qdev-core.h"
9 #include "migration/blocker.h"
10 #include "ui/clipboard.h"
11 #include "ui/console.h"
15 #include "qapi/qapi-types-char.h"
16 #include "qapi/qapi-types-ui.h"
18 #include "spice/vd_agent.h"
20 #define CHECK_SPICE_PROTOCOL_VERSION(major, minor, micro) \
21 (CONFIG_SPICE_PROTOCOL_MAJOR > (major) || \
22 (CONFIG_SPICE_PROTOCOL_MAJOR == (major) && \
23 CONFIG_SPICE_PROTOCOL_MINOR > (minor)) || \
24 (CONFIG_SPICE_PROTOCOL_MAJOR == (major) && \
25 CONFIG_SPICE_PROTOCOL_MINOR == (minor) && \
26 CONFIG_SPICE_PROTOCOL_MICRO >= (micro)))
28 #define VDAGENT_BUFFER_LIMIT (1 * MiB)
29 #define VDAGENT_MOUSE_DEFAULT true
30 #define VDAGENT_CLIPBOARD_DEFAULT false
32 struct VDAgentChardev
{
35 /* TODO: migration isn't yet supported */
36 Error
*migration_blocker
;
53 DeviceState mouse_dev
;
57 uint32_t mouse_display
;
58 QemuInputHandlerState
*mouse_hs
;
61 QemuClipboardPeer cbpeer
;
62 uint32_t last_serial
[QEMU_CLIPBOARD_SELECTION__COUNT
];
63 uint32_t cbpending
[QEMU_CLIPBOARD_SELECTION__COUNT
];
65 typedef struct VDAgentChardev VDAgentChardev
;
67 #define TYPE_CHARDEV_QEMU_VDAGENT "chardev-qemu-vdagent"
69 DECLARE_INSTANCE_CHECKER(VDAgentChardev
, QEMU_VDAGENT_CHARDEV
,
70 TYPE_CHARDEV_QEMU_VDAGENT
);
72 /* ------------------------------------------------------------------ */
73 /* names, for debug logging */
75 static const char *cap_name
[] = {
76 [VD_AGENT_CAP_MOUSE_STATE
] = "mouse-state",
77 [VD_AGENT_CAP_MONITORS_CONFIG
] = "monitors-config",
78 [VD_AGENT_CAP_REPLY
] = "reply",
79 [VD_AGENT_CAP_CLIPBOARD
] = "clipboard",
80 [VD_AGENT_CAP_DISPLAY_CONFIG
] = "display-config",
81 [VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
] = "clipboard-by-demand",
82 [VD_AGENT_CAP_CLIPBOARD_SELECTION
] = "clipboard-selection",
83 [VD_AGENT_CAP_SPARSE_MONITORS_CONFIG
] = "sparse-monitors-config",
84 [VD_AGENT_CAP_GUEST_LINEEND_LF
] = "guest-lineend-lf",
85 [VD_AGENT_CAP_GUEST_LINEEND_CRLF
] = "guest-lineend-crlf",
86 [VD_AGENT_CAP_MAX_CLIPBOARD
] = "max-clipboard",
87 [VD_AGENT_CAP_AUDIO_VOLUME_SYNC
] = "audio-volume-sync",
88 [VD_AGENT_CAP_MONITORS_CONFIG_POSITION
] = "monitors-config-position",
89 [VD_AGENT_CAP_FILE_XFER_DISABLED
] = "file-xfer-disabled",
90 [VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS
] = "file-xfer-detailed-errors",
91 [VD_AGENT_CAP_GRAPHICS_DEVICE_INFO
] = "graphics-device-info",
92 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
93 [VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB
] = "clipboard-no-release-on-regrab",
94 [VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL
] = "clipboard-grab-serial",
98 static const char *msg_name
[] = {
99 [VD_AGENT_MOUSE_STATE
] = "mouse-state",
100 [VD_AGENT_MONITORS_CONFIG
] = "monitors-config",
101 [VD_AGENT_REPLY
] = "reply",
102 [VD_AGENT_CLIPBOARD
] = "clipboard",
103 [VD_AGENT_DISPLAY_CONFIG
] = "display-config",
104 [VD_AGENT_ANNOUNCE_CAPABILITIES
] = "announce-capabilities",
105 [VD_AGENT_CLIPBOARD_GRAB
] = "clipboard-grab",
106 [VD_AGENT_CLIPBOARD_REQUEST
] = "clipboard-request",
107 [VD_AGENT_CLIPBOARD_RELEASE
] = "clipboard-release",
108 [VD_AGENT_FILE_XFER_START
] = "file-xfer-start",
109 [VD_AGENT_FILE_XFER_STATUS
] = "file-xfer-status",
110 [VD_AGENT_FILE_XFER_DATA
] = "file-xfer-data",
111 [VD_AGENT_CLIENT_DISCONNECTED
] = "client-disconnected",
112 [VD_AGENT_MAX_CLIPBOARD
] = "max-clipboard",
113 [VD_AGENT_AUDIO_VOLUME_SYNC
] = "audio-volume-sync",
114 [VD_AGENT_GRAPHICS_DEVICE_INFO
] = "graphics-device-info",
117 static const char *sel_name
[] = {
118 [VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
] = "clipboard",
119 [VD_AGENT_CLIPBOARD_SELECTION_PRIMARY
] = "primary",
120 [VD_AGENT_CLIPBOARD_SELECTION_SECONDARY
] = "secondary",
123 static const char *type_name
[] = {
124 [VD_AGENT_CLIPBOARD_NONE
] = "none",
125 [VD_AGENT_CLIPBOARD_UTF8_TEXT
] = "text",
126 [VD_AGENT_CLIPBOARD_IMAGE_PNG
] = "png",
127 [VD_AGENT_CLIPBOARD_IMAGE_BMP
] = "bmp",
128 [VD_AGENT_CLIPBOARD_IMAGE_TIFF
] = "tiff",
129 [VD_AGENT_CLIPBOARD_IMAGE_JPG
] = "jpg",
130 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 3)
131 [VD_AGENT_CLIPBOARD_FILE_LIST
] = "files",
135 #define GET_NAME(_m, _v) \
136 (((_v) < ARRAY_SIZE(_m) && (_m[_v])) ? (_m[_v]) : "???")
138 /* ------------------------------------------------------------------ */
141 static void vdagent_send_buf(VDAgentChardev
*vd
)
145 while (!buffer_empty(&vd
->outbuf
)) {
146 len
= qemu_chr_be_can_write(CHARDEV(vd
));
150 if (len
> vd
->outbuf
.offset
) {
151 len
= vd
->outbuf
.offset
;
153 qemu_chr_be_write(CHARDEV(vd
), vd
->outbuf
.buffer
, len
);
154 buffer_advance(&vd
->outbuf
, len
);
158 static void vdagent_send_msg(VDAgentChardev
*vd
, VDAgentMessage
*msg
)
160 uint8_t *msgbuf
= (void *)msg
;
161 uint32_t msgsize
= sizeof(VDAgentMessage
) + msg
->size
;
163 VDIChunkHeader chunk
;
165 trace_vdagent_send(GET_NAME(msg_name
, msg
->type
));
167 msg
->protocol
= VD_AGENT_PROTOCOL
;
169 if (vd
->outbuf
.offset
+ msgsize
> VDAGENT_BUFFER_LIMIT
) {
170 error_report("buffer full, dropping message");
174 while (msgoff
< msgsize
) {
175 chunk
.port
= VDP_CLIENT_PORT
;
176 chunk
.size
= msgsize
- msgoff
;
177 if (chunk
.size
> 1024) {
180 buffer_reserve(&vd
->outbuf
, sizeof(chunk
) + chunk
.size
);
181 buffer_append(&vd
->outbuf
, &chunk
, sizeof(chunk
));
182 buffer_append(&vd
->outbuf
, msgbuf
+ msgoff
, chunk
.size
);
183 msgoff
+= chunk
.size
;
185 vdagent_send_buf(vd
);
188 static void vdagent_send_caps(VDAgentChardev
*vd
, bool request
)
190 g_autofree VDAgentMessage
*msg
= g_malloc0(sizeof(VDAgentMessage
) +
191 sizeof(VDAgentAnnounceCapabilities
) +
193 VDAgentAnnounceCapabilities
*caps
= (void *)msg
->data
;
195 msg
->type
= VD_AGENT_ANNOUNCE_CAPABILITIES
;
196 msg
->size
= sizeof(VDAgentAnnounceCapabilities
) + sizeof(uint32_t);
198 caps
->caps
[0] |= (1 << VD_AGENT_CAP_MOUSE_STATE
);
201 caps
->caps
[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
);
202 caps
->caps
[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION
);
203 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
204 caps
->caps
[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL
);
208 caps
->request
= request
;
209 vdagent_send_msg(vd
, msg
);
212 /* ------------------------------------------------------------------ */
215 static bool have_mouse(VDAgentChardev
*vd
)
218 (vd
->caps
& (1 << VD_AGENT_CAP_MOUSE_STATE
));
221 static void vdagent_send_mouse(VDAgentChardev
*vd
)
223 g_autofree VDAgentMessage
*msg
= g_malloc0(sizeof(VDAgentMessage
) +
224 sizeof(VDAgentMouseState
));
225 VDAgentMouseState
*mouse
= (void *)msg
->data
;
227 msg
->type
= VD_AGENT_MOUSE_STATE
;
228 msg
->size
= sizeof(VDAgentMouseState
);
230 mouse
->x
= vd
->mouse_x
;
231 mouse
->y
= vd
->mouse_y
;
232 mouse
->buttons
= vd
->mouse_btn
;
233 mouse
->display_id
= vd
->mouse_display
;
235 vdagent_send_msg(vd
, msg
);
238 static void vdagent_pointer_event(DeviceState
*dev
, QemuConsole
*src
,
241 static const int bmap
[INPUT_BUTTON__MAX
] = {
242 [INPUT_BUTTON_LEFT
] = VD_AGENT_LBUTTON_MASK
,
243 [INPUT_BUTTON_RIGHT
] = VD_AGENT_RBUTTON_MASK
,
244 [INPUT_BUTTON_MIDDLE
] = VD_AGENT_MBUTTON_MASK
,
245 [INPUT_BUTTON_WHEEL_UP
] = VD_AGENT_UBUTTON_MASK
,
246 [INPUT_BUTTON_WHEEL_DOWN
] = VD_AGENT_DBUTTON_MASK
,
247 #ifdef VD_AGENT_EBUTTON_MASK
248 [INPUT_BUTTON_SIDE
] = VD_AGENT_SBUTTON_MASK
,
249 [INPUT_BUTTON_EXTRA
] = VD_AGENT_EBUTTON_MASK
,
253 VDAgentChardev
*vd
= container_of(dev
, struct VDAgentChardev
, mouse_dev
);
254 InputMoveEvent
*move
;
259 case INPUT_EVENT_KIND_ABS
:
260 move
= evt
->u
.abs
.data
;
261 xres
= qemu_console_get_width(src
, 1024);
262 yres
= qemu_console_get_height(src
, 768);
263 if (move
->axis
== INPUT_AXIS_X
) {
264 vd
->mouse_x
= qemu_input_scale_axis(move
->value
,
268 } else if (move
->axis
== INPUT_AXIS_Y
) {
269 vd
->mouse_y
= qemu_input_scale_axis(move
->value
,
274 vd
->mouse_display
= qemu_console_get_index(src
);
277 case INPUT_EVENT_KIND_BTN
:
278 btn
= evt
->u
.btn
.data
;
280 vd
->mouse_btn
|= bmap
[btn
->button
];
282 vd
->mouse_btn
&= ~bmap
[btn
->button
];
292 static void vdagent_pointer_sync(DeviceState
*dev
)
294 VDAgentChardev
*vd
= container_of(dev
, struct VDAgentChardev
, mouse_dev
);
296 if (vd
->caps
& (1 << VD_AGENT_CAP_MOUSE_STATE
)) {
297 vdagent_send_mouse(vd
);
301 static const QemuInputHandler vdagent_mouse_handler
= {
302 .name
= "vdagent mouse",
303 .mask
= INPUT_EVENT_MASK_BTN
| INPUT_EVENT_MASK_ABS
,
304 .event
= vdagent_pointer_event
,
305 .sync
= vdagent_pointer_sync
,
308 /* ------------------------------------------------------------------ */
311 static bool have_clipboard(VDAgentChardev
*vd
)
313 return vd
->clipboard
&&
314 (vd
->caps
& (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
));
317 static bool have_selection(VDAgentChardev
*vd
)
319 return vd
->caps
& (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION
);
322 static uint32_t type_qemu_to_vdagent(enum QemuClipboardType type
)
325 case QEMU_CLIPBOARD_TYPE_TEXT
:
326 return VD_AGENT_CLIPBOARD_UTF8_TEXT
;
328 return VD_AGENT_CLIPBOARD_NONE
;
332 static void vdagent_send_clipboard_grab(VDAgentChardev
*vd
,
333 QemuClipboardInfo
*info
)
335 g_autofree VDAgentMessage
*msg
=
336 g_malloc0(sizeof(VDAgentMessage
) +
337 sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT
+ 1) +
339 uint8_t *s
= msg
->data
;
340 uint32_t *data
= (uint32_t *)msg
->data
;
343 if (have_selection(vd
)) {
344 *s
= info
->selection
;
346 msg
->size
+= sizeof(uint32_t);
347 } else if (info
->selection
!= QEMU_CLIPBOARD_SELECTION_CLIPBOARD
) {
351 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
352 if (vd
->caps
& (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL
)) {
353 if (!info
->has_serial
) {
354 /* client should win */
355 info
->serial
= vd
->last_serial
[info
->selection
]++;
356 info
->has_serial
= true;
358 *data
= info
->serial
;
360 msg
->size
+= sizeof(uint32_t);
364 for (q
= 0; q
< QEMU_CLIPBOARD_TYPE__COUNT
; q
++) {
365 type
= type_qemu_to_vdagent(q
);
366 if (type
!= VD_AGENT_CLIPBOARD_NONE
&& info
->types
[q
].available
) {
369 msg
->size
+= sizeof(uint32_t);
373 msg
->type
= VD_AGENT_CLIPBOARD_GRAB
;
374 vdagent_send_msg(vd
, msg
);
377 static void vdagent_send_clipboard_release(VDAgentChardev
*vd
,
378 QemuClipboardInfo
*info
)
380 g_autofree VDAgentMessage
*msg
= g_malloc0(sizeof(VDAgentMessage
) +
383 if (have_selection(vd
)) {
384 uint8_t *s
= msg
->data
;
385 *s
= info
->selection
;
386 msg
->size
+= sizeof(uint32_t);
387 } else if (info
->selection
!= QEMU_CLIPBOARD_SELECTION_CLIPBOARD
) {
391 msg
->type
= VD_AGENT_CLIPBOARD_RELEASE
;
392 vdagent_send_msg(vd
, msg
);
395 static void vdagent_send_clipboard_data(VDAgentChardev
*vd
,
396 QemuClipboardInfo
*info
,
397 QemuClipboardType type
)
399 g_autofree VDAgentMessage
*msg
= g_malloc0(sizeof(VDAgentMessage
) +
400 sizeof(uint32_t) * 2 +
401 info
->types
[type
].size
);
403 uint8_t *s
= msg
->data
;
404 uint32_t *data
= (uint32_t *)msg
->data
;
406 if (have_selection(vd
)) {
407 *s
= info
->selection
;
409 msg
->size
+= sizeof(uint32_t);
410 } else if (info
->selection
!= QEMU_CLIPBOARD_SELECTION_CLIPBOARD
) {
414 *data
= type_qemu_to_vdagent(type
);
416 msg
->size
+= sizeof(uint32_t);
418 memcpy(data
, info
->types
[type
].data
, info
->types
[type
].size
);
419 msg
->size
+= info
->types
[type
].size
;
421 msg
->type
= VD_AGENT_CLIPBOARD
;
422 vdagent_send_msg(vd
, msg
);
425 static void vdagent_send_empty_clipboard_data(VDAgentChardev
*vd
,
426 QemuClipboardSelection selection
,
427 QemuClipboardType type
)
429 g_autoptr(QemuClipboardInfo
) info
= qemu_clipboard_info_new(&vd
->cbpeer
, selection
);
431 trace_vdagent_send_empty_clipboard();
432 vdagent_send_clipboard_data(vd
, info
, type
);
435 static void vdagent_clipboard_update_info(VDAgentChardev
*vd
,
436 QemuClipboardInfo
*info
)
438 QemuClipboardSelection s
= info
->selection
;
439 QemuClipboardType type
;
440 bool self_update
= info
->owner
== &vd
->cbpeer
;
442 if (info
!= qemu_clipboard_info(s
)) {
443 vd
->cbpending
[s
] = 0;
446 vdagent_send_clipboard_grab(vd
, info
);
448 vdagent_send_clipboard_release(vd
, info
);
458 for (type
= 0; type
< QEMU_CLIPBOARD_TYPE__COUNT
; type
++) {
459 if (vd
->cbpending
[s
] & (1 << type
)) {
460 vd
->cbpending
[s
] &= ~(1 << type
);
461 vdagent_send_clipboard_data(vd
, info
, type
);
466 static void vdagent_clipboard_reset_serial(VDAgentChardev
*vd
)
468 Chardev
*chr
= CHARDEV(vd
);
470 /* reopen the agent connection to reset the serial state */
471 qemu_chr_be_event(chr
, CHR_EVENT_CLOSED
);
472 /* OPENED again after the guest disconnected, see set_fe_open */
475 static void vdagent_clipboard_notify(Notifier
*notifier
, void *data
)
478 container_of(notifier
, VDAgentChardev
, cbpeer
.notifier
);
479 QemuClipboardNotify
*notify
= data
;
481 switch (notify
->type
) {
482 case QEMU_CLIPBOARD_UPDATE_INFO
:
483 vdagent_clipboard_update_info(vd
, notify
->info
);
485 case QEMU_CLIPBOARD_RESET_SERIAL
:
486 vdagent_clipboard_reset_serial(vd
);
491 static void vdagent_clipboard_request(QemuClipboardInfo
*info
,
492 QemuClipboardType qtype
)
494 VDAgentChardev
*vd
= container_of(info
->owner
, VDAgentChardev
, cbpeer
);
495 g_autofree VDAgentMessage
*msg
= g_malloc0(sizeof(VDAgentMessage
) +
496 sizeof(uint32_t) * 2);
497 uint32_t type
= type_qemu_to_vdagent(qtype
);
498 uint8_t *s
= msg
->data
;
499 uint32_t *data
= (uint32_t *)msg
->data
;
501 if (type
== VD_AGENT_CLIPBOARD_NONE
) {
505 if (have_selection(vd
)) {
506 *s
= info
->selection
;
508 msg
->size
+= sizeof(uint32_t);
512 msg
->size
+= sizeof(uint32_t);
514 msg
->type
= VD_AGENT_CLIPBOARD_REQUEST
;
515 vdagent_send_msg(vd
, msg
);
518 static void vdagent_clipboard_recv_grab(VDAgentChardev
*vd
, uint8_t s
, uint32_t size
, void *data
)
520 g_autoptr(QemuClipboardInfo
) info
= NULL
;
522 trace_vdagent_cb_grab_selection(GET_NAME(sel_name
, s
));
523 info
= qemu_clipboard_info_new(&vd
->cbpeer
, s
);
524 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
525 if (vd
->caps
& (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL
)) {
526 if (size
< sizeof(uint32_t)) {
527 /* this shouldn't happen! */
531 info
->has_serial
= true;
532 info
->serial
= *(uint32_t *)data
;
533 if (info
->serial
< vd
->last_serial
[s
]) {
534 trace_vdagent_cb_grab_discard(GET_NAME(sel_name
, s
),
535 vd
->last_serial
[s
], info
->serial
);
536 /* discard lower-ordering guest grab */
539 vd
->last_serial
[s
] = info
->serial
;
540 data
+= sizeof(uint32_t);
541 size
-= sizeof(uint32_t);
544 if (size
> sizeof(uint32_t) * 10) {
546 * spice has 6 types as of 2021. Limiting to 10 entries
547 * so we have some wiggle room.
551 while (size
>= sizeof(uint32_t)) {
552 trace_vdagent_cb_grab_type(GET_NAME(type_name
, *(uint32_t *)data
));
553 switch (*(uint32_t *)data
) {
554 case VD_AGENT_CLIPBOARD_UTF8_TEXT
:
555 info
->types
[QEMU_CLIPBOARD_TYPE_TEXT
].available
= true;
560 data
+= sizeof(uint32_t);
561 size
-= sizeof(uint32_t);
563 qemu_clipboard_update(info
);
566 static void vdagent_clipboard_recv_request(VDAgentChardev
*vd
, uint8_t s
, uint32_t size
, void *data
)
568 QemuClipboardType type
;
569 QemuClipboardInfo
*info
;
571 if (size
< sizeof(uint32_t)) {
574 switch (*(uint32_t *)data
) {
575 case VD_AGENT_CLIPBOARD_UTF8_TEXT
:
576 type
= QEMU_CLIPBOARD_TYPE_TEXT
;
582 info
= qemu_clipboard_info(s
);
583 if (info
&& info
->types
[type
].available
&& info
->owner
!= &vd
->cbpeer
) {
584 if (info
->types
[type
].data
) {
585 vdagent_send_clipboard_data(vd
, info
, type
);
587 vd
->cbpending
[s
] |= (1 << type
);
588 qemu_clipboard_request(info
, type
);
591 vdagent_send_empty_clipboard_data(vd
, s
, type
);
595 static void vdagent_clipboard_recv_data(VDAgentChardev
*vd
, uint8_t s
, uint32_t size
, void *data
)
597 QemuClipboardType type
;
599 if (size
< sizeof(uint32_t)) {
602 switch (*(uint32_t *)data
) {
603 case VD_AGENT_CLIPBOARD_UTF8_TEXT
:
604 type
= QEMU_CLIPBOARD_TYPE_TEXT
;
612 if (qemu_clipboard_peer_owns(&vd
->cbpeer
, s
)) {
613 qemu_clipboard_set_data(&vd
->cbpeer
, qemu_clipboard_info(s
),
614 type
, size
, data
, true);
618 static void vdagent_clipboard_recv_release(VDAgentChardev
*vd
, uint8_t s
)
620 qemu_clipboard_peer_release(&vd
->cbpeer
, s
);
623 static void vdagent_chr_recv_clipboard(VDAgentChardev
*vd
, VDAgentMessage
*msg
)
625 uint8_t s
= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
;
626 uint32_t size
= msg
->size
;
627 void *data
= msg
->data
;
629 if (have_selection(vd
)) {
633 s
= *(uint8_t *)data
;
634 if (s
>= QEMU_CLIPBOARD_SELECTION__COUNT
) {
642 case VD_AGENT_CLIPBOARD_GRAB
:
643 return vdagent_clipboard_recv_grab(vd
, s
, size
, data
);
644 case VD_AGENT_CLIPBOARD_REQUEST
:
645 return vdagent_clipboard_recv_request(vd
, s
, size
, data
);
646 case VD_AGENT_CLIPBOARD
: /* data */
647 return vdagent_clipboard_recv_data(vd
, s
, size
, data
);
648 case VD_AGENT_CLIPBOARD_RELEASE
:
649 return vdagent_clipboard_recv_release(vd
, s
);
651 g_assert_not_reached();
655 /* ------------------------------------------------------------------ */
656 /* chardev backend */
658 static void vdagent_chr_open(Chardev
*chr
,
659 ChardevBackend
*backend
,
663 VDAgentChardev
*vd
= QEMU_VDAGENT_CHARDEV(chr
);
664 ChardevQemuVDAgent
*cfg
= backend
->u
.qemu_vdagent
.data
;
668 * TODO: vdagent protocol is defined to be LE,
669 * so we have to byteswap everything on BE hosts.
671 error_setg(errp
, "vdagent is not supported on bigendian hosts");
675 if (migrate_add_blocker(&vd
->migration_blocker
, errp
) != 0) {
679 vd
->mouse
= VDAGENT_MOUSE_DEFAULT
;
680 if (cfg
->has_mouse
) {
681 vd
->mouse
= cfg
->mouse
;
684 vd
->clipboard
= VDAGENT_CLIPBOARD_DEFAULT
;
685 if (cfg
->has_clipboard
) {
686 vd
->clipboard
= cfg
->clipboard
;
690 vd
->mouse_hs
= qemu_input_handler_register(&vd
->mouse_dev
,
691 &vdagent_mouse_handler
);
697 static void vdagent_chr_recv_caps(VDAgentChardev
*vd
, VDAgentMessage
*msg
)
699 VDAgentAnnounceCapabilities
*caps
= (void *)msg
->data
;
702 if (msg
->size
< (sizeof(VDAgentAnnounceCapabilities
) +
707 for (i
= 0; i
< ARRAY_SIZE(cap_name
); i
++) {
708 if (caps
->caps
[0] & (1 << i
)) {
709 trace_vdagent_peer_cap(GET_NAME(cap_name
, i
));
713 vd
->caps
= caps
->caps
[0];
715 vdagent_send_caps(vd
, false);
717 if (have_mouse(vd
) && vd
->mouse_hs
) {
718 qemu_input_handler_activate(vd
->mouse_hs
);
721 memset(vd
->last_serial
, 0, sizeof(vd
->last_serial
));
723 if (have_clipboard(vd
) && vd
->cbpeer
.notifier
.notify
== NULL
) {
724 qemu_clipboard_reset_serial();
726 vd
->cbpeer
.name
= "vdagent";
727 vd
->cbpeer
.notifier
.notify
= vdagent_clipboard_notify
;
728 vd
->cbpeer
.request
= vdagent_clipboard_request
;
729 qemu_clipboard_peer_register(&vd
->cbpeer
);
733 static void vdagent_chr_recv_msg(VDAgentChardev
*vd
, VDAgentMessage
*msg
)
735 trace_vdagent_recv_msg(GET_NAME(msg_name
, msg
->type
), msg
->size
);
738 case VD_AGENT_ANNOUNCE_CAPABILITIES
:
739 vdagent_chr_recv_caps(vd
, msg
);
741 case VD_AGENT_CLIPBOARD
:
742 case VD_AGENT_CLIPBOARD_GRAB
:
743 case VD_AGENT_CLIPBOARD_REQUEST
:
744 case VD_AGENT_CLIPBOARD_RELEASE
:
745 if (have_clipboard(vd
)) {
746 vdagent_chr_recv_clipboard(vd
, msg
);
754 static void vdagent_reset_xbuf(VDAgentChardev
*vd
)
756 g_clear_pointer(&vd
->xbuf
, g_free
);
761 static void vdagent_chr_recv_chunk(VDAgentChardev
*vd
)
763 VDAgentMessage
*msg
= (void *)vd
->msgbuf
;
766 if (vd
->msgsize
< sizeof(*msg
)) {
767 error_report("%s: message too small: %d < %zd", __func__
,
768 vd
->msgsize
, sizeof(*msg
));
771 if (vd
->msgsize
== msg
->size
+ sizeof(*msg
)) {
772 vdagent_chr_recv_msg(vd
, msg
);
778 vd
->xsize
= msg
->size
+ sizeof(*msg
);
779 vd
->xbuf
= g_malloc0(vd
->xsize
);
782 if (vd
->xoff
+ vd
->msgsize
> vd
->xsize
) {
783 error_report("%s: Oops: %d+%d > %d", __func__
,
784 vd
->xoff
, vd
->msgsize
, vd
->xsize
);
785 vdagent_reset_xbuf(vd
);
789 memcpy(vd
->xbuf
+ vd
->xoff
, vd
->msgbuf
, vd
->msgsize
);
790 vd
->xoff
+= vd
->msgsize
;
791 if (vd
->xoff
< vd
->xsize
) {
795 msg
= (void *)vd
->xbuf
;
796 vdagent_chr_recv_msg(vd
, msg
);
797 vdagent_reset_xbuf(vd
);
800 static void vdagent_reset_bufs(VDAgentChardev
*vd
)
802 memset(&vd
->chunk
, 0, sizeof(vd
->chunk
));
809 static int vdagent_chr_write(Chardev
*chr
, const uint8_t *buf
, int len
)
811 VDAgentChardev
*vd
= QEMU_VDAGENT_CHARDEV(chr
);
812 uint32_t copy
, ret
= len
;
815 if (vd
->chunksize
< sizeof(vd
->chunk
)) {
816 copy
= sizeof(vd
->chunk
) - vd
->chunksize
;
820 memcpy((void *)(&vd
->chunk
) + vd
->chunksize
, buf
, copy
);
821 vd
->chunksize
+= copy
;
824 if (vd
->chunksize
< sizeof(vd
->chunk
)) {
828 assert(vd
->msgbuf
== NULL
);
829 vd
->msgbuf
= g_malloc0(vd
->chunk
.size
);
832 copy
= vd
->chunk
.size
- vd
->msgsize
;
836 memcpy(vd
->msgbuf
+ vd
->msgsize
, buf
, copy
);
841 if (vd
->msgsize
== vd
->chunk
.size
) {
842 trace_vdagent_recv_chunk(vd
->chunk
.size
);
843 vdagent_chr_recv_chunk(vd
);
844 vdagent_reset_bufs(vd
);
851 static void vdagent_chr_accept_input(Chardev
*chr
)
853 VDAgentChardev
*vd
= QEMU_VDAGENT_CHARDEV(chr
);
855 vdagent_send_buf(vd
);
858 static void vdagent_disconnect(VDAgentChardev
*vd
)
860 trace_vdagent_disconnect();
862 buffer_reset(&vd
->outbuf
);
863 vdagent_reset_bufs(vd
);
866 qemu_input_handler_deactivate(vd
->mouse_hs
);
868 if (vd
->cbpeer
.notifier
.notify
) {
869 qemu_clipboard_peer_unregister(&vd
->cbpeer
);
870 memset(&vd
->cbpeer
, 0, sizeof(vd
->cbpeer
));
874 static void vdagent_chr_set_fe_open(struct Chardev
*chr
, int fe_open
)
876 VDAgentChardev
*vd
= QEMU_VDAGENT_CHARDEV(chr
);
878 trace_vdagent_fe_open(fe_open
);
881 trace_vdagent_close();
882 vdagent_disconnect(vd
);
883 /* To reset_serial, we CLOSED our side. Make sure the other end knows we
884 * are ready again. */
885 qemu_chr_be_event(chr
, CHR_EVENT_OPENED
);
889 vdagent_send_caps(vd
, true);
892 static void vdagent_chr_parse(QemuOpts
*opts
, ChardevBackend
*backend
,
895 ChardevQemuVDAgent
*cfg
;
897 backend
->type
= CHARDEV_BACKEND_KIND_QEMU_VDAGENT
;
898 cfg
= backend
->u
.qemu_vdagent
.data
= g_new0(ChardevQemuVDAgent
, 1);
899 qemu_chr_parse_common(opts
, qapi_ChardevQemuVDAgent_base(cfg
));
900 cfg
->has_mouse
= true;
901 cfg
->mouse
= qemu_opt_get_bool(opts
, "mouse", VDAGENT_MOUSE_DEFAULT
);
902 cfg
->has_clipboard
= true;
903 cfg
->clipboard
= qemu_opt_get_bool(opts
, "clipboard", VDAGENT_CLIPBOARD_DEFAULT
);
906 /* ------------------------------------------------------------------ */
908 static void vdagent_chr_class_init(ObjectClass
*oc
, void *data
)
910 ChardevClass
*cc
= CHARDEV_CLASS(oc
);
912 cc
->parse
= vdagent_chr_parse
;
913 cc
->open
= vdagent_chr_open
;
914 cc
->chr_write
= vdagent_chr_write
;
915 cc
->chr_set_fe_open
= vdagent_chr_set_fe_open
;
916 cc
->chr_accept_input
= vdagent_chr_accept_input
;
919 static void vdagent_chr_init(Object
*obj
)
921 VDAgentChardev
*vd
= QEMU_VDAGENT_CHARDEV(obj
);
923 buffer_init(&vd
->outbuf
, "vdagent-outbuf");
924 error_setg(&vd
->migration_blocker
,
925 "The vdagent chardev doesn't yet support migration");
928 static void vdagent_chr_fini(Object
*obj
)
930 VDAgentChardev
*vd
= QEMU_VDAGENT_CHARDEV(obj
);
932 migrate_del_blocker(&vd
->migration_blocker
);
933 vdagent_disconnect(vd
);
935 qemu_input_handler_unregister(vd
->mouse_hs
);
937 buffer_free(&vd
->outbuf
);
940 static const TypeInfo vdagent_chr_type_info
= {
941 .name
= TYPE_CHARDEV_QEMU_VDAGENT
,
942 .parent
= TYPE_CHARDEV
,
943 .instance_size
= sizeof(VDAgentChardev
),
944 .instance_init
= vdagent_chr_init
,
945 .instance_finalize
= vdagent_chr_fini
,
946 .class_init
= vdagent_chr_class_init
,
949 static void register_types(void)
951 type_register_static(&vdagent_chr_type_info
);
954 type_init(register_types
);