1 /* vdagentd.c vdagentd (daemon) code
3 Copyright 2010-2013 Red Hat, Inc.
6 Hans de Goede <hdegoede@redhat.com>
7 Gerd Hoffmann <kraxel@redhat.com>
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #include <sys/select.h>
36 #include <spice/vd_agent.h>
40 #include "vdagentd-proto.h"
41 #include "vdagentd-proto-strings.h"
43 #include "xorg-conf.h"
44 #include "virtio-port.h"
45 #include "session-info.h"
51 struct vdagentd_guest_xorg_resolution
*screen_info
;
56 static const char *pidfilename
= "/var/run/spice-vdagentd/spice-vdagentd.pid";
57 static const char *portdev
= "/dev/virtio-ports/com.redhat.spice.0";
58 static const char *vdagentd_socket
= VDAGENTD_SOCKET
;
59 static const char *uinput_device
= "/dev/uinput";
61 static int uinput_fake
= 0;
62 static int only_once
= 0;
63 static struct udscs_server
*server
= NULL
;
64 static struct vdagent_virtio_port
*virtio_port
= NULL
;
65 static GHashTable
*active_xfers
= NULL
;
66 static struct session_info
*session_info
= NULL
;
67 static struct vdagentd_uinput
*uinput
= NULL
;
68 static VDAgentMonitorsConfig
*mon_config
= NULL
;
69 static uint32_t *capabilities
= NULL
;
70 static int capabilities_size
= 0;
71 static const char *active_session
= NULL
;
72 static unsigned int session_count
= 0;
73 static struct udscs_connection
*active_session_conn
= NULL
;
74 static int agent_owns_clipboard
[256] = { 0, };
76 static int retval
= 0;
77 static int client_connected
= 0;
78 static int max_clipboard
= -1;
80 /* utility functions */
81 /* vdagentd <-> spice-client communication handling */
82 static void send_capabilities(struct vdagent_virtio_port
*vport
,
85 VDAgentAnnounceCapabilities
*caps
;
88 size
= sizeof(*caps
) + VD_AGENT_CAPS_BYTES
;
89 caps
= calloc(1, size
);
91 syslog(LOG_ERR
, "out of memory allocating capabilities array (write)");
95 caps
->request
= request
;
96 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MOUSE_STATE
);
97 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MONITORS_CONFIG
);
98 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_REPLY
);
99 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
);
100 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_SELECTION
);
101 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG
);
102 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_GUEST_LINEEND_LF
);
103 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MAX_CLIPBOARD
);
104 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_AUDIO_VOLUME_SYNC
);
106 vdagent_virtio_port_write(vport
, VDP_CLIENT_PORT
,
107 VD_AGENT_ANNOUNCE_CAPABILITIES
, 0,
108 (uint8_t *)caps
, size
);
112 static void do_client_disconnect(void)
114 if (client_connected
) {
115 udscs_server_write_all(server
, VDAGENTD_CLIENT_DISCONNECTED
, 0, 0,
117 client_connected
= 0;
121 static void do_client_monitors(struct vdagent_virtio_port
*vport
, int port_nr
,
122 VDAgentMessage
*message_header
, VDAgentMonitorsConfig
*new_monitors
)
127 /* Store monitor config to send to agents when they connect */
128 size
= sizeof(VDAgentMonitorsConfig
) +
129 new_monitors
->num_of_monitors
* sizeof(VDAgentMonConfig
);
130 if (message_header
->size
!= size
) {
131 syslog(LOG_ERR
, "invalid message size for VDAgentMonitorsConfig");
135 vdagentd_write_xorg_conf(new_monitors
);
138 mon_config
->num_of_monitors
!= new_monitors
->num_of_monitors
) {
140 mon_config
= malloc(size
);
142 syslog(LOG_ERR
, "out of memory allocating monitors config");
146 memcpy(mon_config
, new_monitors
, size
);
148 /* Send monitor config to currently active agent */
149 if (active_session_conn
)
150 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
151 (uint8_t *)mon_config
, size
);
153 /* Acknowledge reception of monitors config to spice server / client */
154 reply
.type
= VD_AGENT_MONITORS_CONFIG
;
155 reply
.error
= VD_AGENT_SUCCESS
;
156 vdagent_virtio_port_write(vport
, port_nr
, VD_AGENT_REPLY
, 0,
157 (uint8_t *)&reply
, sizeof(reply
));
160 static void do_client_volume_sync(struct vdagent_virtio_port
*vport
, int port_nr
,
161 VDAgentMessage
*message_header
,
162 VDAgentAudioVolumeSync
*avs
)
164 if (active_session_conn
== NULL
) {
165 syslog(LOG_DEBUG
, "No active session - Can't volume-sync");
169 udscs_write(active_session_conn
, VDAGENTD_AUDIO_VOLUME_SYNC
, 0, 0,
170 (uint8_t *)avs
, message_header
->size
);
173 static void do_client_capabilities(struct vdagent_virtio_port
*vport
,
174 VDAgentMessage
*message_header
,
175 VDAgentAnnounceCapabilities
*caps
)
177 int new_size
= VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header
->size
);
179 if (capabilities_size
!= new_size
) {
180 capabilities_size
= new_size
;
182 capabilities
= malloc(capabilities_size
* sizeof(uint32_t));
184 syslog(LOG_ERR
, "oom allocating capabilities array (read)");
185 capabilities_size
= 0;
189 memcpy(capabilities
, caps
->caps
, capabilities_size
* sizeof(uint32_t));
191 /* Report the previous client has disconneced. */
192 do_client_disconnect();
194 syslog(LOG_DEBUG
, "New client connected");
195 client_connected
= 1;
196 send_capabilities(vport
, 0);
200 static void do_client_clipboard(struct vdagent_virtio_port
*vport
,
201 VDAgentMessage
*message_header
, uint8_t *data
)
203 uint32_t msg_type
= 0, data_type
= 0, size
= message_header
->size
;
204 uint8_t selection
= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
;
206 if (!active_session_conn
) {
208 "Could not find an agent connection belonging to the "
209 "active session, ignoring client clipboard request");
213 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
214 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
220 switch (message_header
->type
) {
221 case VD_AGENT_CLIPBOARD_GRAB
:
222 msg_type
= VDAGENTD_CLIPBOARD_GRAB
;
223 agent_owns_clipboard
[selection
] = 0;
225 case VD_AGENT_CLIPBOARD_REQUEST
: {
226 VDAgentClipboardRequest
*req
= (VDAgentClipboardRequest
*)data
;
227 msg_type
= VDAGENTD_CLIPBOARD_REQUEST
;
228 data_type
= req
->type
;
233 case VD_AGENT_CLIPBOARD
: {
234 VDAgentClipboard
*clipboard
= (VDAgentClipboard
*)data
;
235 msg_type
= VDAGENTD_CLIPBOARD_DATA
;
236 data_type
= clipboard
->type
;
237 size
= size
- sizeof(VDAgentClipboard
);
238 data
= clipboard
->data
;
241 case VD_AGENT_CLIPBOARD_RELEASE
:
242 msg_type
= VDAGENTD_CLIPBOARD_RELEASE
;
248 udscs_write(active_session_conn
, msg_type
, selection
, data_type
,
252 /* To be used by vdagentd for failures in file-xfer such as when file-xfer was
253 * cancelled or an error happened */
254 static void send_file_xfer_status(struct vdagent_virtio_port
*vport
,
255 const char *msg
, uint32_t id
, uint32_t xfer_status
)
257 VDAgentFileXferStatusMessage status
= {
259 .result
= xfer_status
,
261 syslog(LOG_WARNING
, msg
, id
);
263 vdagent_virtio_port_write(vport
, VDP_CLIENT_PORT
,
264 VD_AGENT_FILE_XFER_STATUS
, 0,
265 (uint8_t *)&status
, sizeof(status
));
268 static void do_client_file_xfer(struct vdagent_virtio_port
*vport
,
269 VDAgentMessage
*message_header
,
272 uint32_t msg_type
, id
;
273 struct udscs_connection
*conn
;
275 switch (message_header
->type
) {
276 case VD_AGENT_FILE_XFER_START
: {
277 VDAgentFileXferStartMessage
*s
= (VDAgentFileXferStartMessage
*)data
;
278 if (!active_session_conn
) {
279 send_file_xfer_status(vport
,
280 "Could not find an agent connnection belonging to the "
281 "active session, cancelling client file-xfer request %u",
282 s
->id
, VD_AGENT_FILE_XFER_STATUS_CANCELLED
);
284 } else if (session_info_session_is_locked(session_info
)) {
285 syslog(LOG_DEBUG
, "Session is locked, skipping file-xfer-start");
286 send_file_xfer_status(vport
,
287 "User's session is locked and cannot start file transfer. "
288 "Cancelling client file-xfer request %u",
289 s
->id
, VD_AGENT_FILE_XFER_STATUS_ERROR
);
292 udscs_write(active_session_conn
, VDAGENTD_FILE_XFER_START
, 0, 0,
293 data
, message_header
->size
);
296 case VD_AGENT_FILE_XFER_STATUS
: {
297 VDAgentFileXferStatusMessage
*s
= (VDAgentFileXferStatusMessage
*)data
;
298 msg_type
= VDAGENTD_FILE_XFER_STATUS
;
302 case VD_AGENT_FILE_XFER_DATA
: {
303 VDAgentFileXferDataMessage
*d
= (VDAgentFileXferDataMessage
*)data
;
304 msg_type
= VDAGENTD_FILE_XFER_DATA
;
310 conn
= g_hash_table_lookup(active_xfers
, GUINT_TO_POINTER(id
));
313 syslog(LOG_DEBUG
, "Could not find file-xfer %u (cancelled?)", id
);
316 udscs_write(conn
, msg_type
, 0, 0, data
, message_header
->size
);
319 static int virtio_port_read_complete(
320 struct vdagent_virtio_port
*vport
,
322 VDAgentMessage
*message_header
,
325 uint32_t min_size
= 0;
327 if (message_header
->protocol
!= VD_AGENT_PROTOCOL
) {
328 syslog(LOG_ERR
, "message with wrong protocol version ignoring");
332 switch (message_header
->type
) {
333 case VD_AGENT_MOUSE_STATE
:
334 if (message_header
->size
!= sizeof(VDAgentMouseState
))
336 vdagentd_uinput_do_mouse(&uinput
, (VDAgentMouseState
*)data
);
338 /* Try to re-open the tablet */
339 struct agent_data
*agent_data
=
340 udscs_get_user_data(active_session_conn
);
342 uinput
= vdagentd_uinput_create(uinput_device
,
345 agent_data
->screen_info
,
346 agent_data
->screen_count
,
350 syslog(LOG_CRIT
, "Fatal uinput error");
356 case VD_AGENT_MONITORS_CONFIG
:
357 if (message_header
->size
< sizeof(VDAgentMonitorsConfig
))
359 do_client_monitors(vport
, port_nr
, message_header
,
360 (VDAgentMonitorsConfig
*)data
);
362 case VD_AGENT_ANNOUNCE_CAPABILITIES
:
363 if (message_header
->size
< sizeof(VDAgentAnnounceCapabilities
))
365 do_client_capabilities(vport
, message_header
,
366 (VDAgentAnnounceCapabilities
*)data
);
368 case VD_AGENT_CLIPBOARD_GRAB
:
369 case VD_AGENT_CLIPBOARD_REQUEST
:
370 case VD_AGENT_CLIPBOARD
:
371 case VD_AGENT_CLIPBOARD_RELEASE
:
372 switch (message_header
->type
) {
373 case VD_AGENT_CLIPBOARD_GRAB
:
374 min_size
= sizeof(VDAgentClipboardGrab
); break;
375 case VD_AGENT_CLIPBOARD_REQUEST
:
376 min_size
= sizeof(VDAgentClipboardRequest
); break;
377 case VD_AGENT_CLIPBOARD
:
378 min_size
= sizeof(VDAgentClipboard
); break;
380 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
381 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
384 if (message_header
->size
< min_size
) {
387 do_client_clipboard(vport
, message_header
, data
);
389 case VD_AGENT_FILE_XFER_START
:
390 case VD_AGENT_FILE_XFER_STATUS
:
391 case VD_AGENT_FILE_XFER_DATA
:
392 do_client_file_xfer(vport
, message_header
, data
);
394 case VD_AGENT_CLIENT_DISCONNECTED
:
395 vdagent_virtio_port_reset(vport
, VDP_CLIENT_PORT
);
396 do_client_disconnect();
398 case VD_AGENT_MAX_CLIPBOARD
:
399 if (message_header
->size
!= sizeof(VDAgentMaxClipboard
))
401 VDAgentMaxClipboard
*msg
= (VDAgentMaxClipboard
*)data
;
402 syslog(LOG_DEBUG
, "Set max clipboard: %d", msg
->max
);
403 max_clipboard
= msg
->max
;
405 case VD_AGENT_AUDIO_VOLUME_SYNC
:
406 if (message_header
->size
< sizeof(VDAgentAudioVolumeSync
))
409 do_client_volume_sync(vport
, port_nr
, message_header
,
410 (VDAgentAudioVolumeSync
*)data
);
413 syslog(LOG_WARNING
, "unknown message type %d, ignoring",
414 message_header
->type
);
420 syslog(LOG_ERR
, "read: invalid message size: %u for message type: %u",
421 message_header
->size
, message_header
->type
);
425 static void virtio_write_clipboard(uint8_t selection
, uint32_t msg_type
,
426 uint32_t data_type
, const uint8_t *data
, uint32_t data_size
)
428 uint32_t size
= data_size
;
430 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
431 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
434 if (data_type
!= -1) {
438 vdagent_virtio_port_write_start(virtio_port
, VDP_CLIENT_PORT
, msg_type
,
441 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
442 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
443 uint8_t sel
[4] = { selection
, 0, 0, 0 };
444 vdagent_virtio_port_write_append(virtio_port
, sel
, 4);
446 if (data_type
!= -1) {
447 vdagent_virtio_port_write_append(virtio_port
, (uint8_t*)&data_type
, 4);
450 vdagent_virtio_port_write_append(virtio_port
, data
, data_size
);
453 /* vdagentd <-> vdagent communication handling */
454 static int do_agent_clipboard(struct udscs_connection
*conn
,
455 struct udscs_message_header
*header
, const uint8_t *data
)
457 uint8_t selection
= header
->arg1
;
458 uint32_t msg_type
= 0, data_type
= -1, size
= header
->size
;
460 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
461 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
))
464 /* Check that this agent is from the currently active session */
465 if (conn
!= active_session_conn
) {
467 syslog(LOG_DEBUG
, "%p clipboard req from agent which is not in "
468 "the active session?", conn
);
473 syslog(LOG_ERR
, "Clipboard req from agent but no client connection");
477 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
478 VD_AGENT_CAP_CLIPBOARD_SELECTION
) &&
479 selection
!= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
) {
483 switch (header
->type
) {
484 case VDAGENTD_CLIPBOARD_GRAB
:
485 msg_type
= VD_AGENT_CLIPBOARD_GRAB
;
486 agent_owns_clipboard
[selection
] = 1;
488 case VDAGENTD_CLIPBOARD_REQUEST
:
489 msg_type
= VD_AGENT_CLIPBOARD_REQUEST
;
490 data_type
= header
->arg2
;
493 case VDAGENTD_CLIPBOARD_DATA
:
494 msg_type
= VD_AGENT_CLIPBOARD
;
495 data_type
= header
->arg2
;
496 if (max_clipboard
!= -1 && size
> max_clipboard
) {
497 syslog(LOG_WARNING
, "clipboard is too large (%d > %d), discarding",
498 size
, max_clipboard
);
499 virtio_write_clipboard(selection
, msg_type
, data_type
, NULL
, 0);
503 case VDAGENTD_CLIPBOARD_RELEASE
:
504 msg_type
= VD_AGENT_CLIPBOARD_RELEASE
;
506 agent_owns_clipboard
[selection
] = 0;
509 syslog(LOG_WARNING
, "unexpected clipboard message type");
513 if (size
!= header
->size
) {
515 "unexpected extra data in clipboard msg, disconnecting agent");
519 virtio_write_clipboard(selection
, msg_type
, data_type
, data
, header
->size
);
524 if (header
->type
== VDAGENTD_CLIPBOARD_REQUEST
) {
525 /* Let the agent know no answer is coming */
526 udscs_write(conn
, VDAGENTD_CLIPBOARD_DATA
,
527 selection
, VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
532 /* When we open the vdagent virtio channel, the server automatically goes into
533 client mouse mode, so we can only have the channel open when we know the
534 active session resolution. This function checks that we have an agent in the
535 active session, and that it has told us its resolution. If these conditions
536 are met it sets the uinput tablet device's resolution and opens the virtio
537 channel (if it is not already open). If these conditions are not met, it
539 static void check_xorg_resolution(void)
541 struct agent_data
*agent_data
= udscs_get_user_data(active_session_conn
);
543 if (agent_data
&& agent_data
->screen_info
) {
545 uinput
= vdagentd_uinput_create(uinput_device
,
548 agent_data
->screen_info
,
549 agent_data
->screen_count
,
553 vdagentd_uinput_update_size(&uinput
,
556 agent_data
->screen_info
,
557 agent_data
->screen_count
);
559 syslog(LOG_CRIT
, "Fatal uinput error");
566 syslog(LOG_INFO
, "opening vdagent virtio channel");
567 virtio_port
= vdagent_virtio_port_create(portdev
,
568 virtio_port_read_complete
,
571 syslog(LOG_CRIT
, "Fatal error opening vdagent virtio channel");
576 send_capabilities(virtio_port
, 1);
579 #ifndef WITH_STATIC_UINPUT
580 vdagentd_uinput_destroy(&uinput
);
583 vdagent_virtio_port_flush(&virtio_port
);
584 vdagent_virtio_port_destroy(&virtio_port
);
585 syslog(LOG_INFO
, "closed vdagent virtio channel");
590 static int connection_matches_active_session(struct udscs_connection
**connp
,
593 struct udscs_connection
**conn_ret
= (struct udscs_connection
**)priv
;
594 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
596 /* Check if this connection matches the currently active session */
597 if (!agent_data
->session
|| !active_session
)
599 if (strcmp(agent_data
->session
, active_session
))
606 static void release_clipboards(void)
610 for (sel
= 0; sel
< VD_AGENT_CLIPBOARD_SELECTION_SECONDARY
; ++sel
) {
611 if (agent_owns_clipboard
[sel
] && virtio_port
) {
612 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
613 VD_AGENT_CLIPBOARD_RELEASE
, 0, &sel
, 1);
615 agent_owns_clipboard
[sel
] = 0;
619 static void update_active_session_connection(struct udscs_connection
*new_conn
)
624 active_session
= session_info_get_active_session(session_info
);
625 session_count
= udscs_server_for_all_clients(server
,
626 connection_matches_active_session
,
635 if (new_conn
&& session_count
!= 1) {
636 syslog(LOG_ERR
, "multiple agents in one session, "
637 "disabling agent to avoid potential information leak");
641 if (new_conn
== active_session_conn
)
644 active_session_conn
= new_conn
;
646 syslog(LOG_DEBUG
, "%p is now the active session", new_conn
);
648 if (active_session_conn
&& !session_info_is_user(session_info
)) {
650 syslog(LOG_DEBUG
, "New session agent does not belong to user: "
651 "disabling file-xfer");
652 udscs_write(active_session_conn
, VDAGENTD_FILE_XFER_DISABLE
, 0, 0,
656 if (active_session_conn
&& mon_config
)
657 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
658 (uint8_t *)mon_config
, sizeof(VDAgentMonitorsConfig
) +
659 mon_config
->num_of_monitors
* sizeof(VDAgentMonConfig
));
661 release_clipboards();
663 check_xorg_resolution();
666 static gboolean
remove_active_xfers(gpointer key
, gpointer value
, gpointer conn
)
669 send_file_xfer_status(virtio_port
,
670 "Agent disc; cancelling file-xfer %u",
671 GPOINTER_TO_UINT(key
),
672 VD_AGENT_FILE_XFER_STATUS_CANCELLED
);
678 static void agent_connect(struct udscs_connection
*conn
)
680 struct agent_data
*agent_data
;
682 agent_data
= calloc(1, sizeof(*agent_data
));
684 syslog(LOG_ERR
, "Out of memory allocating agent data, disconnecting");
685 udscs_destroy_connection(&conn
);
690 uint32_t pid
= udscs_get_peer_cred(conn
).pid
;
691 agent_data
->session
= session_info_session_for_pid(session_info
, pid
);
694 udscs_set_user_data(conn
, (void *)agent_data
);
695 udscs_write(conn
, VDAGENTD_VERSION
, 0, 0,
696 (uint8_t *)VERSION
, strlen(VERSION
) + 1);
697 update_active_session_connection(conn
);
700 static void agent_disconnect(struct udscs_connection
*conn
)
702 struct agent_data
*agent_data
= udscs_get_user_data(conn
);
704 g_hash_table_foreach_remove(active_xfers
, remove_active_xfers
, conn
);
706 free(agent_data
->session
);
707 agent_data
->session
= NULL
;
708 update_active_session_connection(NULL
);
710 free(agent_data
->screen_info
);
714 static void agent_read_complete(struct udscs_connection
**connp
,
715 struct udscs_message_header
*header
, uint8_t *data
)
717 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
719 switch (header
->type
) {
720 case VDAGENTD_GUEST_XORG_RESOLUTION
: {
721 struct vdagentd_guest_xorg_resolution
*res
;
722 int n
= header
->size
/ sizeof(*res
);
724 /* Detect older version session agent, but don't disconnect, as
725 that stops it from getting the VDAGENTD_VERSION message, and then
726 it will never re-exec the new version... */
727 if (header
->arg1
== 0 && header
->arg2
== 0) {
728 syslog(LOG_INFO
, "got old session agent xorg resolution message, "
734 if (header
->size
!= n
* sizeof(*res
)) {
735 syslog(LOG_ERR
, "guest xorg resolution message has wrong size, "
736 "disconnecting agent");
737 udscs_destroy_connection(connp
);
742 free(agent_data
->screen_info
);
743 res
= malloc(n
* sizeof(*res
));
745 syslog(LOG_ERR
, "out of memory allocating screen info");
748 memcpy(res
, data
, n
* sizeof(*res
));
749 agent_data
->width
= header
->arg1
;
750 agent_data
->height
= header
->arg2
;
751 agent_data
->screen_info
= res
;
752 agent_data
->screen_count
= n
;
754 check_xorg_resolution();
757 case VDAGENTD_CLIPBOARD_GRAB
:
758 case VDAGENTD_CLIPBOARD_REQUEST
:
759 case VDAGENTD_CLIPBOARD_DATA
:
760 case VDAGENTD_CLIPBOARD_RELEASE
:
761 if (do_agent_clipboard(*connp
, header
, data
)) {
762 udscs_destroy_connection(connp
);
767 case VDAGENTD_FILE_XFER_STATUS
:{
768 VDAgentFileXferStatusMessage status
;
769 status
.id
= header
->arg1
;
770 status
.result
= header
->arg2
;
771 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
772 VD_AGENT_FILE_XFER_STATUS
, 0,
773 (uint8_t *)&status
, sizeof(status
));
774 if (status
.result
== VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA
)
775 g_hash_table_insert(active_xfers
, GUINT_TO_POINTER(status
.id
),
778 g_hash_table_remove(active_xfers
, GUINT_TO_POINTER(status
.id
));
783 syslog(LOG_ERR
, "unknown message from vdagent: %u, ignoring",
791 static void usage(FILE *fp
)
794 "Usage: spice-vdagentd [OPTIONS]\n\n"
795 "Spice guest agent daemon, version %s.\n\n"
797 " -h print this text\n"
798 " -d log debug messages (use twice for extra info)\n"
799 " -s <port> set virtio serial port [%s]\n"
800 " -S <filename> set udcs socket [%s]\n"
801 " -u <dev> set uinput device [%s]\n"
802 " -f treat uinput device as fake; no ioctls\n"
803 " -x don't daemonize\n"
804 " -o Only handle one virtio serial session.\n"
805 #ifdef HAVE_CONSOLE_KIT
806 " -X Disable console kit integration\n"
808 #ifdef HAVE_LIBSYSTEMD_LOGIN
809 " -X Disable systemd-logind integration\n"
811 ,VERSION
, portdev
, vdagentd_socket
, uinput_device
);
814 static void daemonize(void)
819 /* detach from terminal */
822 close(0); close(1); close(2);
824 x
= open("/dev/null", O_RDWR
); x
= dup(x
); x
= dup(x
);
825 pidfile
= fopen(pidfilename
, "w");
827 fprintf(pidfile
, "%d\n", (int)getpid());
832 syslog(LOG_ERR
, "fork: %m");
835 udscs_destroy_server(server
);
840 static void main_loop(void)
842 fd_set readfds
, writefds
;
851 nfds
= udscs_server_fill_fds(server
, &readfds
, &writefds
);
852 n
= vdagent_virtio_port_fill_fds(virtio_port
, &readfds
, &writefds
);
857 ck_fd
= session_info_get_fd(session_info
);
858 FD_SET(ck_fd
, &readfds
);
863 n
= select(nfds
, &readfds
, &writefds
, NULL
, NULL
);
867 syslog(LOG_CRIT
, "Fatal error select: %m");
872 udscs_server_handle_fds(server
, &readfds
, &writefds
);
876 vdagent_virtio_port_handle_fds(&virtio_port
, &readfds
, &writefds
);
878 int old_client_connected
= client_connected
;
880 "AIIEEE lost spice client connection, reconnecting");
881 virtio_port
= vdagent_virtio_port_create(portdev
,
882 virtio_port_read_complete
,
886 "Fatal error opening vdagent virtio channel");
890 do_client_disconnect();
891 client_connected
= old_client_connected
;
894 else if (only_once
&& once
)
896 syslog(LOG_INFO
, "Exiting after one client session.");
900 if (session_info
&& FD_ISSET(ck_fd
, &readfds
)) {
901 active_session
= session_info_get_active_session(session_info
);
902 update_active_session_connection(NULL
);
907 static void quit_handler(int sig
)
912 int main(int argc
, char *argv
[])
915 int do_daemonize
= 1;
916 int want_session_info
= 1;
917 struct sigaction act
;
920 if (-1 == (c
= getopt(argc
, argv
, "-dhxXfos:u:S:")))
930 vdagentd_socket
= optarg
;
933 uinput_device
= optarg
;
945 want_session_info
= 0;
957 memset(&act
, 0, sizeof(act
));
958 act
.sa_flags
= SA_RESTART
;
959 act
.sa_handler
= quit_handler
;
960 sigaction(SIGINT
, &act
, NULL
);
961 sigaction(SIGHUP
, &act
, NULL
);
962 sigaction(SIGTERM
, &act
, NULL
);
963 sigaction(SIGQUIT
, &act
, NULL
);
965 openlog("spice-vdagentd", do_daemonize
? 0 : LOG_PERROR
, LOG_USER
);
967 /* Setup communication with vdagent process(es) */
968 server
= udscs_create_server(vdagentd_socket
, agent_connect
,
969 agent_read_complete
, agent_disconnect
,
970 vdagentd_messages
, VDAGENTD_NO_MESSAGES
,
973 syslog(LOG_CRIT
, "Fatal could not create server socket %s",
977 if (chmod(vdagentd_socket
, 0666)) {
978 syslog(LOG_CRIT
, "Fatal could not change permissions on %s: %m",
980 udscs_destroy_server(server
);
987 #ifdef WITH_STATIC_UINPUT
988 uinput
= vdagentd_uinput_create(uinput_device
, 1024, 768, NULL
, 0,
989 debug
> 1, uinput_fake
);
991 udscs_destroy_server(server
);
996 if (want_session_info
)
997 session_info
= session_info_create(debug
);
999 syslog(LOG_WARNING
, "no session info, max 1 session agent allowed");
1001 active_xfers
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
1004 release_clipboards();
1006 vdagentd_uinput_destroy(&uinput
);
1007 vdagent_virtio_port_flush(&virtio_port
);
1008 vdagent_virtio_port_destroy(&virtio_port
);
1009 session_info_destroy(session_info
);
1010 udscs_destroy_server(server
);
1011 if (unlink(vdagentd_socket
) != 0)
1012 syslog(LOG_ERR
, "unlink %s: %s", vdagentd_socket
, strerror(errno
));
1013 syslog(LOG_INFO
, "vdagentd quiting, returning status %d", retval
);
1016 unlink(pidfilename
);