vdagent: Mark vdagent and vdagentd functions static
[vd_agent.git] / src / vdagentd.c
bloba493baf18ed190376c2370992f5b8743a62eaad3
1 /* vdagentd.c vdagentd (daemon) code
3 Copyright 2010-2013 Red Hat, Inc.
5 Red Hat Authors:
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/>.
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <syslog.h>
34 #include <sys/select.h>
35 #include <sys/stat.h>
36 #include <spice/vd_agent.h>
37 #include <glib.h>
39 #include "udscs.h"
40 #include "vdagentd-proto.h"
41 #include "vdagentd-proto-strings.h"
42 #include "vdagentd-uinput.h"
43 #include "vdagentd-xorg-conf.h"
44 #include "vdagent-virtio-port.h"
45 #include "session-info.h"
47 struct agent_data {
48 char *session;
49 int width;
50 int height;
51 struct vdagentd_guest_xorg_resolution *screen_info;
52 int screen_count;
55 /* variables */
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";
60 static int debug = 0;
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, };
75 static int quit = 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,
83 uint32_t request)
85 VDAgentAnnounceCapabilities *caps;
86 uint32_t size;
88 size = sizeof(*caps) + VD_AGENT_CAPS_BYTES;
89 caps = calloc(1, size);
90 if (!caps) {
91 syslog(LOG_ERR, "out of memory allocating capabilities array (write)");
92 return;
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);
109 free(caps);
112 static void do_client_disconnect(void)
114 if (client_connected) {
115 udscs_server_write_all(server, VDAGENTD_CLIENT_DISCONNECTED, 0, 0,
116 NULL, 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)
124 VDAgentReply reply;
125 uint32_t size;
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");
132 return;
135 vdagentd_write_xorg_conf(new_monitors);
137 if (!mon_config ||
138 mon_config->num_of_monitors != new_monitors->num_of_monitors) {
139 free(mon_config);
140 mon_config = malloc(size);
141 if (!mon_config) {
142 syslog(LOG_ERR, "out of memory allocating monitors config");
143 return;
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");
166 return;
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;
181 free(capabilities);
182 capabilities = malloc(capabilities_size * sizeof(uint32_t));
183 if (!capabilities) {
184 syslog(LOG_ERR, "oom allocating capabilities array (read)");
185 capabilities_size = 0;
186 return;
189 memcpy(capabilities, caps->caps, capabilities_size * sizeof(uint32_t));
190 if (caps->request) {
191 /* Report the previous client has disconneced. */
192 do_client_disconnect();
193 if (debug)
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) {
207 syslog(LOG_WARNING,
208 "Could not find an agent connection belonging to the "
209 "active session, ignoring client clipboard request");
210 return;
213 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
214 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
215 selection = data[0];
216 data += 4;
217 size -= 4;
220 switch (message_header->type) {
221 case VD_AGENT_CLIPBOARD_GRAB:
222 msg_type = VDAGENTD_CLIPBOARD_GRAB;
223 agent_owns_clipboard[selection] = 0;
224 break;
225 case VD_AGENT_CLIPBOARD_REQUEST: {
226 VDAgentClipboardRequest *req = (VDAgentClipboardRequest *)data;
227 msg_type = VDAGENTD_CLIPBOARD_REQUEST;
228 data_type = req->type;
229 data = NULL;
230 size = 0;
231 break;
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;
239 break;
241 case VD_AGENT_CLIPBOARD_RELEASE:
242 msg_type = VDAGENTD_CLIPBOARD_RELEASE;
243 data = NULL;
244 size = 0;
245 break;
248 udscs_write(active_session_conn, msg_type, selection, data_type,
249 data, size);
252 static void cancel_file_xfer(struct vdagent_virtio_port *vport,
253 const char *msg, uint32_t id)
255 VDAgentFileXferStatusMessage status = {
256 .id = id,
257 .result = VD_AGENT_FILE_XFER_STATUS_CANCELLED,
259 syslog(LOG_WARNING, msg, id);
260 if (vport)
261 vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
262 VD_AGENT_FILE_XFER_STATUS, 0,
263 (uint8_t *)&status, sizeof(status));
266 static void do_client_file_xfer(struct vdagent_virtio_port *vport,
267 VDAgentMessage *message_header,
268 uint8_t *data)
270 uint32_t msg_type, id;
271 struct udscs_connection *conn;
273 switch (message_header->type) {
274 case VD_AGENT_FILE_XFER_START: {
275 VDAgentFileXferStartMessage *s = (VDAgentFileXferStartMessage *)data;
276 if (!active_session_conn) {
277 cancel_file_xfer(vport,
278 "Could not find an agent connnection belonging to the "
279 "active session, cancelling client file-xfer request %u",
280 s->id);
281 return;
283 udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, 0, 0,
284 data, message_header->size);
285 return;
287 case VD_AGENT_FILE_XFER_STATUS: {
288 VDAgentFileXferStatusMessage *s = (VDAgentFileXferStatusMessage *)data;
289 msg_type = VDAGENTD_FILE_XFER_STATUS;
290 id = s->id;
291 break;
293 case VD_AGENT_FILE_XFER_DATA: {
294 VDAgentFileXferDataMessage *d = (VDAgentFileXferDataMessage *)data;
295 msg_type = VDAGENTD_FILE_XFER_DATA;
296 id = d->id;
297 break;
301 conn = g_hash_table_lookup(active_xfers, GUINT_TO_POINTER(id));
302 if (!conn) {
303 if (debug)
304 syslog(LOG_DEBUG, "Could not find file-xfer %u (cancelled?)", id);
305 return;
307 udscs_write(conn, msg_type, 0, 0, data, message_header->size);
310 static int virtio_port_read_complete(
311 struct vdagent_virtio_port *vport,
312 int port_nr,
313 VDAgentMessage *message_header,
314 uint8_t *data)
316 uint32_t min_size = 0;
318 if (message_header->protocol != VD_AGENT_PROTOCOL) {
319 syslog(LOG_ERR, "message with wrong protocol version ignoring");
320 return 0;
323 switch (message_header->type) {
324 case VD_AGENT_MOUSE_STATE:
325 if (message_header->size != sizeof(VDAgentMouseState))
326 goto size_error;
327 vdagentd_uinput_do_mouse(&uinput, (VDAgentMouseState *)data);
328 if (!uinput) {
329 /* Try to re-open the tablet */
330 struct agent_data *agent_data =
331 udscs_get_user_data(active_session_conn);
332 if (agent_data)
333 uinput = vdagentd_uinput_create(uinput_device,
334 agent_data->width,
335 agent_data->height,
336 agent_data->screen_info,
337 agent_data->screen_count,
338 debug > 1,
339 uinput_fake);
340 if (!uinput) {
341 syslog(LOG_CRIT, "Fatal uinput error");
342 retval = 1;
343 quit = 1;
346 break;
347 case VD_AGENT_MONITORS_CONFIG:
348 if (message_header->size < sizeof(VDAgentMonitorsConfig))
349 goto size_error;
350 do_client_monitors(vport, port_nr, message_header,
351 (VDAgentMonitorsConfig *)data);
352 break;
353 case VD_AGENT_ANNOUNCE_CAPABILITIES:
354 if (message_header->size < sizeof(VDAgentAnnounceCapabilities))
355 goto size_error;
356 do_client_capabilities(vport, message_header,
357 (VDAgentAnnounceCapabilities *)data);
358 break;
359 case VD_AGENT_CLIPBOARD_GRAB:
360 case VD_AGENT_CLIPBOARD_REQUEST:
361 case VD_AGENT_CLIPBOARD:
362 case VD_AGENT_CLIPBOARD_RELEASE:
363 switch (message_header->type) {
364 case VD_AGENT_CLIPBOARD_GRAB:
365 min_size = sizeof(VDAgentClipboardGrab); break;
366 case VD_AGENT_CLIPBOARD_REQUEST:
367 min_size = sizeof(VDAgentClipboardRequest); break;
368 case VD_AGENT_CLIPBOARD:
369 min_size = sizeof(VDAgentClipboard); break;
371 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
372 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
373 min_size += 4;
375 if (message_header->size < min_size) {
376 goto size_error;
378 do_client_clipboard(vport, message_header, data);
379 break;
380 case VD_AGENT_FILE_XFER_START:
381 case VD_AGENT_FILE_XFER_STATUS:
382 case VD_AGENT_FILE_XFER_DATA:
383 do_client_file_xfer(vport, message_header, data);
384 break;
385 case VD_AGENT_CLIENT_DISCONNECTED:
386 vdagent_virtio_port_reset(vport, VDP_CLIENT_PORT);
387 do_client_disconnect();
388 break;
389 case VD_AGENT_MAX_CLIPBOARD:
390 if (message_header->size != sizeof(VDAgentMaxClipboard))
391 goto size_error;
392 VDAgentMaxClipboard *msg = (VDAgentMaxClipboard *)data;
393 syslog(LOG_DEBUG, "Set max clipboard: %d", msg->max);
394 max_clipboard = msg->max;
395 break;
396 case VD_AGENT_AUDIO_VOLUME_SYNC:
397 if (message_header->size < sizeof(VDAgentAudioVolumeSync))
398 goto size_error;
400 do_client_volume_sync(vport, port_nr, message_header,
401 (VDAgentAudioVolumeSync *)data);
402 break;
403 default:
404 syslog(LOG_WARNING, "unknown message type %d, ignoring",
405 message_header->type);
408 return 0;
410 size_error:
411 syslog(LOG_ERR, "read: invalid message size: %u for message type: %u",
412 message_header->size, message_header->type);
413 return 0;
416 static void virtio_write_clipboard(uint8_t selection, uint32_t msg_type,
417 uint32_t data_type, const uint8_t *data, uint32_t data_size)
419 uint32_t size = data_size;
421 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
422 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
423 size += 4;
425 if (data_type != -1) {
426 size += 4;
429 vdagent_virtio_port_write_start(virtio_port, VDP_CLIENT_PORT, msg_type,
430 0, size);
432 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
433 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
434 uint8_t sel[4] = { selection, 0, 0, 0 };
435 vdagent_virtio_port_write_append(virtio_port, sel, 4);
437 if (data_type != -1) {
438 vdagent_virtio_port_write_append(virtio_port, (uint8_t*)&data_type, 4);
441 vdagent_virtio_port_write_append(virtio_port, data, data_size);
444 /* vdagentd <-> vdagent communication handling */
445 static int do_agent_clipboard(struct udscs_connection *conn,
446 struct udscs_message_header *header, const uint8_t *data)
448 uint8_t selection = header->arg1;
449 uint32_t msg_type = 0, data_type = -1, size = header->size;
451 if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
452 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND))
453 goto error;
455 /* Check that this agent is from the currently active session */
456 if (conn != active_session_conn) {
457 if (debug)
458 syslog(LOG_DEBUG, "%p clipboard req from agent which is not in "
459 "the active session?", conn);
460 goto error;
463 if (!virtio_port) {
464 syslog(LOG_ERR, "Clipboard req from agent but no client connection");
465 goto error;
468 if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
469 VD_AGENT_CAP_CLIPBOARD_SELECTION) &&
470 selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
471 goto error;
474 switch (header->type) {
475 case VDAGENTD_CLIPBOARD_GRAB:
476 msg_type = VD_AGENT_CLIPBOARD_GRAB;
477 agent_owns_clipboard[selection] = 1;
478 break;
479 case VDAGENTD_CLIPBOARD_REQUEST:
480 msg_type = VD_AGENT_CLIPBOARD_REQUEST;
481 data_type = header->arg2;
482 size = 0;
483 break;
484 case VDAGENTD_CLIPBOARD_DATA:
485 msg_type = VD_AGENT_CLIPBOARD;
486 data_type = header->arg2;
487 if (max_clipboard != -1 && size > max_clipboard) {
488 syslog(LOG_WARNING, "clipboard is too large (%d > %d), discarding",
489 size, max_clipboard);
490 virtio_write_clipboard(selection, msg_type, data_type, NULL, 0);
491 return 0;
493 break;
494 case VDAGENTD_CLIPBOARD_RELEASE:
495 msg_type = VD_AGENT_CLIPBOARD_RELEASE;
496 size = 0;
497 agent_owns_clipboard[selection] = 0;
498 break;
499 default:
500 syslog(LOG_WARNING, "unexpected clipboard message type");
501 goto error;
504 if (size != header->size) {
505 syslog(LOG_ERR,
506 "unexpected extra data in clipboard msg, disconnecting agent");
507 return -1;
510 virtio_write_clipboard(selection, msg_type, data_type, data, header->size);
512 return 0;
514 error:
515 if (header->type == VDAGENTD_CLIPBOARD_REQUEST) {
516 /* Let the agent know no answer is coming */
517 udscs_write(conn, VDAGENTD_CLIPBOARD_DATA,
518 selection, VD_AGENT_CLIPBOARD_NONE, NULL, 0);
520 return 0;
523 /* When we open the vdagent virtio channel, the server automatically goes into
524 client mouse mode, so we can only have the channel open when we know the
525 active session resolution. This function checks that we have an agent in the
526 active session, and that it has told us its resolution. If these conditions
527 are met it sets the uinput tablet device's resolution and opens the virtio
528 channel (if it is not already open). If these conditions are not met, it
529 closes both. */
530 static void check_xorg_resolution(void)
532 struct agent_data *agent_data = udscs_get_user_data(active_session_conn);
534 if (agent_data && agent_data->screen_info) {
535 if (!uinput)
536 uinput = vdagentd_uinput_create(uinput_device,
537 agent_data->width,
538 agent_data->height,
539 agent_data->screen_info,
540 agent_data->screen_count,
541 debug > 1,
542 uinput_fake);
543 else
544 vdagentd_uinput_update_size(&uinput,
545 agent_data->width,
546 agent_data->height,
547 agent_data->screen_info,
548 agent_data->screen_count);
549 if (!uinput) {
550 syslog(LOG_CRIT, "Fatal uinput error");
551 retval = 1;
552 quit = 1;
553 return;
556 if (!virtio_port) {
557 syslog(LOG_INFO, "opening vdagent virtio channel");
558 virtio_port = vdagent_virtio_port_create(portdev,
559 virtio_port_read_complete,
560 NULL);
561 if (!virtio_port) {
562 syslog(LOG_CRIT, "Fatal error opening vdagent virtio channel");
563 retval = 1;
564 quit = 1;
565 return;
567 send_capabilities(virtio_port, 1);
569 } else {
570 #ifndef WITH_STATIC_UINPUT
571 vdagentd_uinput_destroy(&uinput);
572 #endif
573 if (virtio_port) {
574 vdagent_virtio_port_flush(&virtio_port);
575 vdagent_virtio_port_destroy(&virtio_port);
576 syslog(LOG_INFO, "closed vdagent virtio channel");
581 static int connection_matches_active_session(struct udscs_connection **connp,
582 void *priv)
584 struct udscs_connection **conn_ret = (struct udscs_connection **)priv;
585 struct agent_data *agent_data = udscs_get_user_data(*connp);
587 /* Check if this connection matches the currently active session */
588 if (!agent_data->session || !active_session)
589 return 0;
590 if (strcmp(agent_data->session, active_session))
591 return 0;
593 *conn_ret = *connp;
594 return 1;
597 static void release_clipboards(void)
599 uint8_t sel;
601 for (sel = 0; sel < VD_AGENT_CLIPBOARD_SELECTION_SECONDARY; ++sel) {
602 if (agent_owns_clipboard[sel] && virtio_port) {
603 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
604 VD_AGENT_CLIPBOARD_RELEASE, 0, &sel, 1);
606 agent_owns_clipboard[sel] = 0;
610 static void update_active_session_connection(struct udscs_connection *new_conn)
612 if (session_info) {
613 new_conn = NULL;
614 if (!active_session)
615 active_session = session_info_get_active_session(session_info);
616 session_count = udscs_server_for_all_clients(server,
617 connection_matches_active_session,
618 (void*)&new_conn);
619 } else {
620 if (new_conn)
621 session_count++;
622 else
623 session_count--;
626 if (new_conn && session_count != 1) {
627 syslog(LOG_ERR, "multiple agents in one session, "
628 "disabling agent to avoid potential information leak");
629 new_conn = NULL;
632 if (new_conn == active_session_conn)
633 return;
635 active_session_conn = new_conn;
636 if (debug)
637 syslog(LOG_DEBUG, "%p is now the active session", new_conn);
638 if (active_session_conn && mon_config)
639 udscs_write(active_session_conn, VDAGENTD_MONITORS_CONFIG, 0, 0,
640 (uint8_t *)mon_config, sizeof(VDAgentMonitorsConfig) +
641 mon_config->num_of_monitors * sizeof(VDAgentMonConfig));
643 release_clipboards();
645 check_xorg_resolution();
648 static gboolean remove_active_xfers(gpointer key, gpointer value, gpointer conn)
650 if (value == conn) {
651 cancel_file_xfer(virtio_port, "Agent disc; cancelling file-xfer %u",
652 GPOINTER_TO_UINT(key));
653 return 1;
654 } else
655 return 0;
658 static void agent_connect(struct udscs_connection *conn)
660 struct agent_data *agent_data;
662 agent_data = calloc(1, sizeof(*agent_data));
663 if (!agent_data) {
664 syslog(LOG_ERR, "Out of memory allocating agent data, disconnecting");
665 udscs_destroy_connection(&conn);
666 return;
669 if (session_info) {
670 uint32_t pid = udscs_get_peer_cred(conn).pid;
671 agent_data->session = session_info_session_for_pid(session_info, pid);
674 udscs_set_user_data(conn, (void *)agent_data);
675 udscs_write(conn, VDAGENTD_VERSION, 0, 0,
676 (uint8_t *)VERSION, strlen(VERSION) + 1);
677 update_active_session_connection(conn);
680 static void agent_disconnect(struct udscs_connection *conn)
682 struct agent_data *agent_data = udscs_get_user_data(conn);
684 g_hash_table_foreach_remove(active_xfers, remove_active_xfers, conn);
686 free(agent_data->session);
687 agent_data->session = NULL;
688 update_active_session_connection(NULL);
690 free(agent_data->screen_info);
691 free(agent_data);
694 static void agent_read_complete(struct udscs_connection **connp,
695 struct udscs_message_header *header, uint8_t *data)
697 struct agent_data *agent_data = udscs_get_user_data(*connp);
699 switch (header->type) {
700 case VDAGENTD_GUEST_XORG_RESOLUTION: {
701 struct vdagentd_guest_xorg_resolution *res;
702 int n = header->size / sizeof(*res);
704 /* Detect older version session agent, but don't disconnect, as
705 that stops it from getting the VDAGENTD_VERSION message, and then
706 it will never re-exec the new version... */
707 if (header->arg1 == 0 && header->arg2 == 0) {
708 syslog(LOG_INFO, "got old session agent xorg resolution message, "
709 "ignoring");
710 free(data);
711 return;
714 if (header->size != n * sizeof(*res)) {
715 syslog(LOG_ERR, "guest xorg resolution message has wrong size, "
716 "disconnecting agent");
717 udscs_destroy_connection(connp);
718 free(data);
719 return;
722 free(agent_data->screen_info);
723 res = malloc(n * sizeof(*res));
724 if (!res) {
725 syslog(LOG_ERR, "out of memory allocating screen info");
726 n = 0;
728 memcpy(res, data, n * sizeof(*res));
729 agent_data->width = header->arg1;
730 agent_data->height = header->arg2;
731 agent_data->screen_info = res;
732 agent_data->screen_count = n;
734 check_xorg_resolution();
735 break;
737 case VDAGENTD_CLIPBOARD_GRAB:
738 case VDAGENTD_CLIPBOARD_REQUEST:
739 case VDAGENTD_CLIPBOARD_DATA:
740 case VDAGENTD_CLIPBOARD_RELEASE:
741 if (do_agent_clipboard(*connp, header, data)) {
742 udscs_destroy_connection(connp);
743 free(data);
744 return;
746 break;
747 case VDAGENTD_FILE_XFER_STATUS:{
748 VDAgentFileXferStatusMessage status;
749 status.id = header->arg1;
750 status.result = header->arg2;
751 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
752 VD_AGENT_FILE_XFER_STATUS, 0,
753 (uint8_t *)&status, sizeof(status));
754 if (status.result == VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA)
755 g_hash_table_insert(active_xfers, GUINT_TO_POINTER(status.id),
756 *connp);
757 else
758 g_hash_table_remove(active_xfers, GUINT_TO_POINTER(status.id));
759 break;
762 default:
763 syslog(LOG_ERR, "unknown message from vdagent: %u, ignoring",
764 header->type);
766 free(data);
769 /* main */
771 static void usage(FILE *fp)
773 fprintf(fp,
774 "Usage: spice-vdagentd [OPTIONS]\n\n"
775 "Spice guest agent daemon, version %s.\n\n"
776 "Options:\n"
777 " -h print this text\n"
778 " -d log debug messages (use twice for extra info)\n"
779 " -s <port> set virtio serial port [%s]\n"
780 " -S <filename> set udcs socket [%s]\n"
781 " -u <dev> set uinput device [%s]\n"
782 " -f treat uinput device as fake; no ioctls\n"
783 " -x don't daemonize\n"
784 " -o Only handle one virtio serial session.\n"
785 #ifdef HAVE_CONSOLE_KIT
786 " -X Disable console kit integration\n"
787 #endif
788 #ifdef HAVE_LIBSYSTEMD_LOGIN
789 " -X Disable systemd-logind integration\n"
790 #endif
791 ,VERSION, portdev, vdagentd_socket, uinput_device);
794 static void daemonize(void)
796 int x;
797 FILE *pidfile;
799 /* detach from terminal */
800 switch (fork()) {
801 case 0:
802 close(0); close(1); close(2);
803 setsid();
804 x = open("/dev/null", O_RDWR); x = dup(x); x = dup(x);
805 pidfile = fopen(pidfilename, "w");
806 if (pidfile) {
807 fprintf(pidfile, "%d\n", (int)getpid());
808 fclose(pidfile);
810 break;
811 case -1:
812 syslog(LOG_ERR, "fork: %m");
813 retval = 1;
814 default:
815 udscs_destroy_server(server);
816 exit(retval);
820 static void main_loop(void)
822 fd_set readfds, writefds;
823 int n, nfds;
824 int ck_fd = 0;
825 int once = 0;
827 while (!quit) {
828 FD_ZERO(&readfds);
829 FD_ZERO(&writefds);
831 nfds = udscs_server_fill_fds(server, &readfds, &writefds);
832 n = vdagent_virtio_port_fill_fds(virtio_port, &readfds, &writefds);
833 if (n >= nfds)
834 nfds = n + 1;
836 if (session_info) {
837 ck_fd = session_info_get_fd(session_info);
838 FD_SET(ck_fd, &readfds);
839 if (ck_fd >= nfds)
840 nfds = ck_fd + 1;
843 n = select(nfds, &readfds, &writefds, NULL, NULL);
844 if (n == -1) {
845 if (errno == EINTR)
846 continue;
847 syslog(LOG_CRIT, "Fatal error select: %m");
848 retval = 1;
849 break;
852 udscs_server_handle_fds(server, &readfds, &writefds);
854 if (virtio_port) {
855 once = 1;
856 vdagent_virtio_port_handle_fds(&virtio_port, &readfds, &writefds);
857 if (!virtio_port) {
858 int old_client_connected = client_connected;
859 syslog(LOG_CRIT,
860 "AIIEEE lost spice client connection, reconnecting");
861 virtio_port = vdagent_virtio_port_create(portdev,
862 virtio_port_read_complete,
863 NULL);
864 if (!virtio_port) {
865 syslog(LOG_CRIT,
866 "Fatal error opening vdagent virtio channel");
867 retval = 1;
868 break;
870 do_client_disconnect();
871 client_connected = old_client_connected;
874 else if (only_once && once)
876 syslog(LOG_INFO, "Exiting after one client session.");
877 break;
880 if (session_info && FD_ISSET(ck_fd, &readfds)) {
881 active_session = session_info_get_active_session(session_info);
882 update_active_session_connection(NULL);
887 static void quit_handler(int sig)
889 quit = 1;
892 int main(int argc, char *argv[])
894 int c;
895 int do_daemonize = 1;
896 int want_session_info = 1;
897 struct sigaction act;
899 for (;;) {
900 if (-1 == (c = getopt(argc, argv, "-dhxXfos:u:S:")))
901 break;
902 switch (c) {
903 case 'd':
904 debug++;
905 break;
906 case 's':
907 portdev = optarg;
908 break;
909 case 'S':
910 vdagentd_socket = optarg;
911 break;
912 case 'u':
913 uinput_device = optarg;
914 break;
915 case 'f':
916 uinput_fake = 1;
917 break;
918 case 'o':
919 only_once = 1;
920 break;
921 case 'x':
922 do_daemonize = 0;
923 break;
924 case 'X':
925 want_session_info = 0;
926 break;
927 case 'h':
928 usage(stdout);
929 return 0;
930 default:
931 fputs("\n", stderr);
932 usage(stderr);
933 return 1;
937 memset(&act, 0, sizeof(act));
938 act.sa_flags = SA_RESTART;
939 act.sa_handler = quit_handler;
940 sigaction(SIGINT, &act, NULL);
941 sigaction(SIGHUP, &act, NULL);
942 sigaction(SIGTERM, &act, NULL);
943 sigaction(SIGQUIT, &act, NULL);
945 openlog("spice-vdagentd", do_daemonize ? 0 : LOG_PERROR, LOG_USER);
947 /* Setup communication with vdagent process(es) */
948 server = udscs_create_server(vdagentd_socket, agent_connect,
949 agent_read_complete, agent_disconnect,
950 vdagentd_messages, VDAGENTD_NO_MESSAGES,
951 debug);
952 if (!server) {
953 syslog(LOG_CRIT, "Fatal could not create server socket %s",
954 vdagentd_socket);
955 return 1;
957 if (chmod(vdagentd_socket, 0666)) {
958 syslog(LOG_CRIT, "Fatal could not change permissions on %s: %m",
959 vdagentd_socket);
960 udscs_destroy_server(server);
961 return 1;
964 if (do_daemonize)
965 daemonize();
967 #ifdef WITH_STATIC_UINPUT
968 uinput = vdagentd_uinput_create(uinput_device, 1024, 768, NULL, 0,
969 debug > 1, uinput_fake);
970 if (!uinput) {
971 udscs_destroy_server(server);
972 return 1;
974 #endif
976 if (want_session_info)
977 session_info = session_info_create(debug);
978 if (!session_info)
979 syslog(LOG_WARNING, "no session info, max 1 session agent allowed");
981 active_xfers = g_hash_table_new(g_direct_hash, g_direct_equal);
982 main_loop();
984 release_clipboards();
986 vdagentd_uinput_destroy(&uinput);
987 vdagent_virtio_port_flush(&virtio_port);
988 vdagent_virtio_port_destroy(&virtio_port);
989 session_info_destroy(session_info);
990 udscs_destroy_server(server);
991 if (unlink(vdagentd_socket) != 0)
992 syslog(LOG_ERR, "unlink %s: %s", vdagentd_socket, strerror(errno));
993 syslog(LOG_INFO, "vdagentd quiting, returning status %d", retval);
995 if (do_daemonize)
996 unlink(pidfilename);
998 return retval;