x11: get PRIMARY clipboard atom
[vd_agent.git] / vdagentd.c
blob6365552ec36ba666b254f138e3f6b1e4e50a3368
1 /* vdagentd.c vdagentd (daemon) code
3 Copyright 2010 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/>.
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <sys/select.h>
31 #include <sys/stat.h>
32 #include <spice/vd_agent.h>
34 #include "udscs.h"
35 #include "vdagentd-proto.h"
36 #include "vdagentd-proto-strings.h"
37 #include "vdagentd-uinput.h"
38 #include "vdagent-virtio-port.h"
39 #include "console-kit.h"
41 struct agent_data {
42 char *session;
43 int width;
44 int height;
47 /* variables */
48 static const char *logfilename = "/var/log/spice-vdagentd/spice-vdagentd.log";
49 static const char *pidfilename = "/var/run/spice-vdagentd/spice-vdagentd.pid";
50 static const char *portdev = "/dev/virtio-ports/com.redhat.spice.0";
51 static const char *uinput_device = "/dev/uinput";
52 static int debug = 0;
53 static struct udscs_server *server = NULL;
54 static struct vdagent_virtio_port *virtio_port = NULL;
55 static struct console_kit *console_kit = NULL;
56 static struct vdagentd_uinput *uinput = NULL;
57 static VDAgentMonitorsConfig *mon_config = NULL;
58 static uint32_t *capabilities = NULL;
59 static int capabilities_size = 0;
60 static const char *active_session = NULL;
61 static struct udscs_connection *active_session_conn = NULL;
62 static int agent_owns_clipboard = 0;
63 static FILE *logfile = NULL;
64 static int quit = 0;
65 static int retval = 0;
67 /* utility functions */
68 /* vdagentd <-> spice-client communication handling */
69 static void send_capabilities(struct vdagent_virtio_port *vport,
70 uint32_t request)
72 VDAgentAnnounceCapabilities *caps;
73 uint32_t size;
75 size = sizeof(*caps) + VD_AGENT_CAPS_BYTES;
76 caps = calloc(1, size);
77 if (!caps) {
78 fprintf(logfile,
79 "out of memory allocating capabilities array (write)\n");
80 return;
83 caps->request = request;
84 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MOUSE_STATE);
85 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG);
86 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY);
87 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
89 vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
90 VD_AGENT_ANNOUNCE_CAPABILITIES, 0,
91 (uint8_t *)caps, size);
92 free(caps);
95 static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
96 VDAgentMessage *message_header, VDAgentMonitorsConfig *new_monitors)
98 VDAgentReply reply;
99 uint32_t size;
101 /* Store monitor config to send to agents when they connect */
102 size = sizeof(VDAgentMonitorsConfig) +
103 new_monitors->num_of_monitors * sizeof(VDAgentMonConfig);
104 if (message_header->size != size) {
105 fprintf(logfile, "invalid message size for VDAgentMonitorsConfig\n");
106 return;
109 if (!mon_config ||
110 mon_config->num_of_monitors != new_monitors->num_of_monitors) {
111 free(mon_config);
112 mon_config = malloc(size);
113 if (!mon_config) {
114 fprintf(logfile, "out of memory allocating monitors config\n");
115 return;
118 memcpy(mon_config, new_monitors, size);
120 /* Send monitor config to currently connected agents */
121 udscs_server_write_all(server, VDAGENTD_MONITORS_CONFIG, 0,
122 (uint8_t *)mon_config, size);
124 /* Acknowledge reception of monitors config to spice server / client */
125 reply.type = VD_AGENT_MONITORS_CONFIG;
126 reply.error = VD_AGENT_SUCCESS;
127 vdagent_virtio_port_write(vport, port_nr, VD_AGENT_REPLY, 0,
128 (uint8_t *)&reply, sizeof(reply));
131 static void do_client_capabilities(struct vdagent_virtio_port *vport,
132 VDAgentMessage *message_header,
133 VDAgentAnnounceCapabilities *caps)
135 int new_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header->size);
137 if (capabilities_size != new_size) {
138 capabilities_size = new_size;
139 free(capabilities);
140 capabilities = malloc(capabilities_size * sizeof(uint32_t));
141 if (!capabilities) {
142 fprintf(logfile,
143 "out of memory allocating capabilities array (read)\n");
144 capabilities_size = 0;
145 return;
148 memcpy(capabilities, caps->caps, capabilities_size * sizeof(uint32_t));
149 if (caps->request)
150 send_capabilities(vport, 0);
153 static void do_client_clipboard(struct vdagent_virtio_port *vport,
154 VDAgentMessage *message_header, uint8_t *message_data)
156 uint32_t type = 0, opaque = 0, size = 0;
157 uint8_t *data = NULL;
159 if (!active_session_conn) {
160 fprintf(logfile,
161 "Could not find an agent connnection belonging to the "
162 "active session, ignoring client clipboard request\n");
163 return;
166 switch (message_header->type) {
167 case VD_AGENT_CLIPBOARD_GRAB:
168 type = VDAGENTD_CLIPBOARD_GRAB;
169 data = message_data;
170 size = message_header->size;
171 agent_owns_clipboard = 0;
172 break;
173 case VD_AGENT_CLIPBOARD_REQUEST: {
174 VDAgentClipboardRequest *req = (VDAgentClipboardRequest *)message_data;
175 type = VDAGENTD_CLIPBOARD_REQUEST;
176 opaque = req->type;
177 break;
179 case VD_AGENT_CLIPBOARD: {
180 VDAgentClipboard *clipboard = (VDAgentClipboard *)message_data;
181 type = VDAGENTD_CLIPBOARD_DATA;
182 opaque = clipboard->type;
183 size = message_header->size - sizeof(VDAgentClipboard);
184 data = clipboard->data;
185 break;
187 case VD_AGENT_CLIPBOARD_RELEASE:
188 type = VDAGENTD_CLIPBOARD_RELEASE;
189 break;
192 udscs_write(active_session_conn, type, opaque, data, size);
195 int virtio_port_read_complete(
196 struct vdagent_virtio_port *vport,
197 int port_nr,
198 VDAgentMessage *message_header,
199 uint8_t *data)
201 uint32_t min_size = 0;
203 if (message_header->protocol != VD_AGENT_PROTOCOL) {
204 fprintf(logfile, "message with wrong protocol version ignoring\n");
205 return 0;
208 switch (message_header->type) {
209 case VD_AGENT_MOUSE_STATE:
210 if (message_header->size != sizeof(VDAgentMouseState))
211 goto size_error;
212 vdagentd_uinput_do_mouse(&uinput, (VDAgentMouseState *)data);
213 if (!uinput) {
214 /* Try to re-open the tablet */
215 struct agent_data *agent_data =
216 udscs_get_user_data(active_session_conn);
217 if (agent_data)
218 uinput = vdagentd_uinput_create(uinput_device,
219 agent_data->width,
220 agent_data->height,
221 logfile, debug > 1);
222 if (!uinput) {
223 fprintf(logfile, "Fatal uinput error\n");
224 retval = 1;
225 quit = 1;
228 break;
229 case VD_AGENT_MONITORS_CONFIG:
230 if (message_header->size < sizeof(VDAgentMonitorsConfig))
231 goto size_error;
232 do_client_monitors(vport, port_nr, message_header,
233 (VDAgentMonitorsConfig *)data);
234 break;
235 case VD_AGENT_ANNOUNCE_CAPABILITIES:
236 if (message_header->size < sizeof(VDAgentAnnounceCapabilities))
237 goto size_error;
238 do_client_capabilities(vport, message_header,
239 (VDAgentAnnounceCapabilities *)data);
240 break;
241 case VD_AGENT_CLIPBOARD_GRAB:
242 case VD_AGENT_CLIPBOARD_REQUEST:
243 case VD_AGENT_CLIPBOARD:
244 case VD_AGENT_CLIPBOARD_RELEASE:
245 switch (message_header->type) {
246 case VD_AGENT_CLIPBOARD_GRAB:
247 min_size = sizeof(VDAgentClipboardGrab); break;
248 case VD_AGENT_CLIPBOARD_REQUEST:
249 min_size = sizeof(VDAgentClipboardRequest); break;
250 case VD_AGENT_CLIPBOARD:
251 min_size = sizeof(VDAgentClipboard); break;
253 if (message_header->size < min_size)
254 goto size_error;
255 do_client_clipboard(vport, message_header, data);
256 break;
257 default:
258 if (debug)
259 fprintf(logfile, "unknown message type %d\n", message_header->type);
260 break;
263 return 0;
265 size_error:
266 fprintf(logfile, "read: invalid message size: %u for message type: %u\n",
267 message_header->size, message_header->type);
268 return 0;
271 /* vdagentd <-> vdagent communication handling */
272 void do_agent_clipboard(struct udscs_connection *conn,
273 struct udscs_message_header *header, const uint8_t *data)
275 if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
276 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND))
277 goto error;
279 /* Check that this agent is from the currently active session */
280 if (conn != active_session_conn) {
281 fprintf(logfile, "Clipboard request from agent "
282 "which is not in the active session?\n");
283 goto error;
286 if (!virtio_port) {
287 fprintf(logfile,
288 "Clipboard request from agent but no client connection\n");
289 goto error;
292 switch (header->type) {
293 case VDAGENTD_CLIPBOARD_GRAB:
294 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
295 VD_AGENT_CLIPBOARD_GRAB, 0,
296 data, header->size);
297 agent_owns_clipboard = 1;
298 break;
299 case VDAGENTD_CLIPBOARD_REQUEST: {
300 VDAgentClipboardRequest req = { .type = header->opaque };
301 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
302 VD_AGENT_CLIPBOARD_REQUEST, 0,
303 (uint8_t *)&req, sizeof(req));
304 break;
306 case VDAGENTD_CLIPBOARD_DATA: {
307 VDAgentClipboard *clipboard;
308 uint32_t size = sizeof(*clipboard) + header->size;
310 clipboard = calloc(1, size);
311 if (!clipboard) {
312 fprintf(logfile,
313 "out of memory allocating clipboard (write)\n");
314 return;
316 clipboard->type = header->opaque;
317 memcpy(clipboard->data, data, header->size);
319 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
320 VD_AGENT_CLIPBOARD, 0,
321 (uint8_t *)clipboard, size);
322 free(clipboard);
323 break;
325 case VDAGENTD_CLIPBOARD_RELEASE:
326 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
327 VD_AGENT_CLIPBOARD_RELEASE, 0, NULL, 0);
328 agent_owns_clipboard = 0;
329 break;
332 return;
334 error:
335 if (header->type == VDAGENTD_CLIPBOARD_REQUEST) {
336 /* Let the agent know no answer is coming */
337 udscs_write(conn, VDAGENTD_CLIPBOARD_DATA,
338 VD_AGENT_CLIPBOARD_NONE, NULL, 0);
342 /* When we open the vdagent virtio channel, the server automatically goes into
343 client mouse mode, so we can only have the channel open when we know the
344 active session resolution. This function checks that we have an agent in the
345 active session, and that it has told us its resolution. If these conditions
346 are met it sets the uinput tablet device's resolution and opens the virtio
347 channel (if it is not already open). If these conditions are not met, it
348 closes both. */
349 static void check_xorg_resolution(void) {
350 struct agent_data *agent_data = udscs_get_user_data(active_session_conn);
352 if (agent_data && agent_data->width) {
353 if (!uinput)
354 uinput = vdagentd_uinput_create(uinput_device,
355 agent_data->width,
356 agent_data->height,
357 logfile, debug > 1);
358 else
359 vdagentd_uinput_update_size(&uinput, agent_data->width,
360 agent_data->height);
361 if (!uinput) {
362 fprintf(logfile, "Fatal uinput error\n");
363 retval = 1;
364 quit = 1;
365 return;
368 if (!virtio_port) {
369 fprintf(logfile, "opening vdagent virtio channel\n");
370 virtio_port = vdagent_virtio_port_create(portdev,
371 virtio_port_read_complete,
372 NULL, logfile);
373 if (!virtio_port) {
374 fprintf(logfile,
375 "Fatal error opening vdagent virtio channel\n");
376 retval = 1;
377 quit = 1;
378 return;
380 send_capabilities(virtio_port, 1);
382 } else {
383 vdagentd_uinput_destroy(&uinput);
384 if (virtio_port) {
385 vdagent_virtio_port_flush(&virtio_port);
386 vdagent_virtio_port_destroy(&virtio_port);
387 fprintf(logfile, "closed vdagent virtio channel\n");
392 static int connection_matches_active_session(struct udscs_connection **connp,
393 void *priv)
395 struct udscs_connection **conn_ret = (struct udscs_connection **)priv;
396 struct agent_data *agent_data = udscs_get_user_data(*connp);
398 /* Check if this connection matches the currently active session */
399 if (!agent_data->session || !active_session)
400 return 0;
401 if (strcmp(agent_data->session, active_session))
402 return 0;
404 *conn_ret = *connp;
405 return 1;
408 void update_active_session_connection(void)
410 struct udscs_connection *new_conn = NULL;
411 int n;
413 if (!active_session)
414 active_session = console_kit_get_active_session(console_kit);
416 n = udscs_server_for_all_clients(server, connection_matches_active_session,
417 (void*)&new_conn);
418 if (n != 1)
419 new_conn = NULL;
421 if (new_conn == active_session_conn)
422 return;
424 active_session_conn = new_conn;
426 if (agent_owns_clipboard && virtio_port)
427 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
428 VD_AGENT_CLIPBOARD_RELEASE, 0, NULL, 0);
429 agent_owns_clipboard = 0;
431 check_xorg_resolution();
434 void agent_connect(struct udscs_connection *conn)
436 uint32_t pid;
437 struct agent_data *agent_data;
439 agent_data = calloc(1, sizeof(*agent_data));
440 if (!agent_data) {
441 fprintf(logfile, "Out of memory allocating agent data, disconnecting\n");
442 udscs_destroy_connection(&conn);
443 return;
446 pid = udscs_get_peer_cred(conn).pid;
447 agent_data->session = console_kit_session_for_pid(console_kit, pid);
448 udscs_set_user_data(conn, (void *)agent_data);
449 update_active_session_connection();
451 if (mon_config)
452 udscs_write(conn, VDAGENTD_MONITORS_CONFIG, 0, (uint8_t *)mon_config,
453 sizeof(VDAgentMonitorsConfig) +
454 mon_config->num_of_monitors * sizeof(VDAgentMonConfig));
457 void agent_disconnect(struct udscs_connection *conn)
459 struct agent_data *agent_data = udscs_get_user_data(conn);
461 free(agent_data->session);
462 agent_data->session = NULL;
463 update_active_session_connection();
465 free(agent_data);
468 void agent_read_complete(struct udscs_connection **connp,
469 struct udscs_message_header *header, uint8_t *data)
471 struct agent_data *agent_data = udscs_get_user_data(*connp);
473 switch (header->type) {
474 case VDAGENTD_GUEST_XORG_RESOLUTION: {
475 struct vdagentd_guest_xorg_resolution *res =
476 (struct vdagentd_guest_xorg_resolution *)data;
478 if (header->size != sizeof(*res)) {
479 fprintf(logfile,
480 "guest xorg resolution message has wrong size, disconnecting agent\n");
481 udscs_destroy_connection(connp);
482 return;
485 agent_data->width = res->width;
486 agent_data->height = res->height;
487 check_xorg_resolution();
488 break;
490 case VDAGENTD_CLIPBOARD_GRAB:
491 case VDAGENTD_CLIPBOARD_REQUEST:
492 case VDAGENTD_CLIPBOARD_DATA:
493 case VDAGENTD_CLIPBOARD_RELEASE:
494 do_agent_clipboard(*connp, header, data);
495 break;
496 default:
497 fprintf(logfile, "unknown message from vdagent: %u, ignoring\n",
498 header->type);
500 free(data);
503 /* main */
505 static void usage(FILE *fp)
507 fprintf(fp,
508 "vdagentd\n"
509 "options:\n"
510 " -h print this text\n"
511 " -d log debug messages (use twice for extra info)\n"
512 " -s <port> set virtio serial port [%s]\n"
513 " -u <dev> set uinput device [%s]\n"
514 " -x don't daemonize (and log to logfile)\n",
515 portdev, uinput_device);
518 void daemonize(void)
520 int x;
521 FILE *pidfile;
523 /* detach from terminal */
524 switch (fork()) {
525 case 0:
526 close(0); close(1); close(2);
527 setsid();
528 x = open("/dev/null", O_RDWR); dup(x); dup(x);
529 pidfile = fopen(pidfilename, "w");
530 if (pidfile) {
531 fprintf(pidfile, "%d\n", (int)getpid());
532 fclose(pidfile);
534 break;
535 case -1:
536 fprintf(logfile, "fork: %s\n", strerror(errno));
537 retval = 1;
538 default:
539 udscs_destroy_server(server);
540 if (logfile != stderr)
541 fclose(logfile);
542 exit(retval);
546 void main_loop(void)
548 fd_set readfds, writefds;
549 int n, nfds, ck_fd = 0;
551 while (!quit) {
552 FD_ZERO(&readfds);
553 FD_ZERO(&writefds);
555 nfds = udscs_server_fill_fds(server, &readfds, &writefds);
556 n = vdagent_virtio_port_fill_fds(virtio_port, &readfds, &writefds);
557 if (n >= nfds)
558 nfds = n + 1;
560 ck_fd = console_kit_get_fd(console_kit);
561 FD_SET(ck_fd, &readfds);
562 if (ck_fd >= nfds)
563 nfds = ck_fd + 1;
565 n = select(nfds, &readfds, &writefds, NULL, NULL);
566 if (n == -1) {
567 if (errno == EINTR)
568 continue;
569 fprintf(logfile, "Fatal error select: %s\n", strerror(errno));
570 retval = 1;
571 break;
574 udscs_server_handle_fds(server, &readfds, &writefds);
576 if (virtio_port) {
577 vdagent_virtio_port_handle_fds(&virtio_port, &readfds, &writefds);
578 if (!virtio_port) {
579 fprintf(logfile,
580 "AIIEEE lost spice client connection, reconnecting\n");
581 virtio_port = vdagent_virtio_port_create(portdev,
582 virtio_port_read_complete,
583 NULL, logfile);
585 if (!virtio_port) {
586 fprintf(logfile,
587 "Fatal error opening vdagent virtio channel\n");
588 retval = 1;
589 break;
593 if (FD_ISSET(ck_fd, &readfds)) {
594 active_session = console_kit_get_active_session(console_kit);
595 update_active_session_connection();
597 fflush(logfile);
601 static void quit_handler(int sig)
603 quit = 1;
606 int main(int argc, char *argv[])
608 int c;
609 int do_daemonize = 1;
610 struct sigaction act;
612 for (;;) {
613 if (-1 == (c = getopt(argc, argv, "-dhxs:u:")))
614 break;
615 switch (c) {
616 case 'd':
617 debug++;
618 break;
619 case 's':
620 portdev = optarg;
621 break;
622 case 'u':
623 uinput_device = optarg;
624 break;
625 case 'x':
626 do_daemonize = 0;
627 break;
628 case 'h':
629 usage(stdout);
630 return 0;
631 default:
632 usage(stderr);
633 return 1;
637 memset(&act, 0, sizeof(act));
638 act.sa_flags = SA_RESTART;
639 act.sa_handler = quit_handler;
640 sigaction(SIGINT, &act, NULL);
641 sigaction(SIGHUP, &act, NULL);
642 sigaction(SIGTERM, &act, NULL);
643 sigaction(SIGQUIT, &act, NULL);
645 if (do_daemonize) {
646 logfile = fopen(logfilename, "a");
647 if (!logfile) {
648 fprintf(stderr, "Error opening %s: %s\n", logfilename,
649 strerror(errno));
650 logfile = stderr;
652 } else
653 logfile = stderr;
655 /* Setup communication with vdagent process(es) */
656 server = udscs_create_server(VDAGENTD_SOCKET, agent_connect,
657 agent_read_complete, agent_disconnect,
658 vdagentd_messages, VDAGENTD_NO_MESSAGES,
659 debug? logfile:NULL, logfile);
660 if (!server) {
661 fprintf(logfile, "Fatal could not create server socket %s\n",
662 VDAGENTD_SOCKET);
663 if (logfile != stderr)
664 fclose(logfile);
665 return 1;
667 if (chmod(VDAGENTD_SOCKET, 0666)) {
668 fprintf(logfile, "Fatal could not change permissions on %s: %s\n",
669 VDAGENTD_SOCKET, strerror(errno));
670 udscs_destroy_server(server);
671 if (logfile != stderr)
672 fclose(logfile);
673 return 1;
676 if (do_daemonize)
677 daemonize();
679 console_kit = console_kit_create(logfile);
680 if (!console_kit) {
681 fprintf(logfile, "Fatal could not connect to console kit\n");
682 udscs_destroy_server(server);
683 if (logfile != stderr)
684 fclose(logfile);
685 return 1;
688 main_loop();
690 if (agent_owns_clipboard && virtio_port)
691 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
692 VD_AGENT_CLIPBOARD_RELEASE, 0, NULL, 0);
694 vdagentd_uinput_destroy(&uinput);
695 vdagent_virtio_port_flush(&virtio_port);
696 vdagent_virtio_port_destroy(&virtio_port);
697 console_kit_destroy(console_kit);
698 udscs_destroy_server(server);
699 if (unlink(VDAGENTD_SOCKET) != 0)
700 fprintf(logfile, "unlink %s: %s\n", VDAGENTD_SOCKET, strerror(errno));
701 fprintf(logfile, "vdagentd quiting, returning status %d\n", retval);
702 if (logfile != stderr)
703 fclose(logfile);
705 if (do_daemonize)
706 unlink(pidfilename);
708 return retval;