]> git.proxmox.com Git - qemu.git/blob - ui/spice-core.c
spice: core bits
[qemu.git] / ui / spice-core.c
1 /*
2 * Copyright (C) 2010 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 or
7 * (at your option) version 3 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <spice.h>
19 #include <spice-experimental.h>
20
21 #include "qemu-common.h"
22 #include "qemu-spice.h"
23 #include "qemu-timer.h"
24 #include "qemu-queue.h"
25 #include "monitor.h"
26
27 /* core bits */
28
29 static SpiceServer *spice_server;
30 int using_spice = 0;
31
32 struct SpiceTimer {
33 QEMUTimer *timer;
34 QTAILQ_ENTRY(SpiceTimer) next;
35 };
36 static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
37
38 static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
39 {
40 SpiceTimer *timer;
41
42 timer = qemu_mallocz(sizeof(*timer));
43 timer->timer = qemu_new_timer(rt_clock, func, opaque);
44 QTAILQ_INSERT_TAIL(&timers, timer, next);
45 return timer;
46 }
47
48 static void timer_start(SpiceTimer *timer, uint32_t ms)
49 {
50 qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms);
51 }
52
53 static void timer_cancel(SpiceTimer *timer)
54 {
55 qemu_del_timer(timer->timer);
56 }
57
58 static void timer_remove(SpiceTimer *timer)
59 {
60 qemu_del_timer(timer->timer);
61 qemu_free_timer(timer->timer);
62 QTAILQ_REMOVE(&timers, timer, next);
63 qemu_free(timer);
64 }
65
66 struct SpiceWatch {
67 int fd;
68 int event_mask;
69 SpiceWatchFunc func;
70 void *opaque;
71 QTAILQ_ENTRY(SpiceWatch) next;
72 };
73 static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches);
74
75 static void watch_read(void *opaque)
76 {
77 SpiceWatch *watch = opaque;
78 watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
79 }
80
81 static void watch_write(void *opaque)
82 {
83 SpiceWatch *watch = opaque;
84 watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
85 }
86
87 static void watch_update_mask(SpiceWatch *watch, int event_mask)
88 {
89 IOHandler *on_read = NULL;
90 IOHandler *on_write = NULL;
91
92 watch->event_mask = event_mask;
93 if (watch->event_mask & SPICE_WATCH_EVENT_READ) {
94 on_read = watch_read;
95 }
96 if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
97 on_read = watch_write;
98 }
99 qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
100 }
101
102 static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
103 {
104 SpiceWatch *watch;
105
106 watch = qemu_mallocz(sizeof(*watch));
107 watch->fd = fd;
108 watch->func = func;
109 watch->opaque = opaque;
110 QTAILQ_INSERT_TAIL(&watches, watch, next);
111
112 watch_update_mask(watch, event_mask);
113 return watch;
114 }
115
116 static void watch_remove(SpiceWatch *watch)
117 {
118 watch_update_mask(watch, 0);
119 QTAILQ_REMOVE(&watches, watch, next);
120 qemu_free(watch);
121 }
122
123 static SpiceCoreInterface core_interface = {
124 .base.type = SPICE_INTERFACE_CORE,
125 .base.description = "qemu core services",
126 .base.major_version = SPICE_INTERFACE_CORE_MAJOR,
127 .base.minor_version = SPICE_INTERFACE_CORE_MINOR,
128
129 .timer_add = timer_add,
130 .timer_start = timer_start,
131 .timer_cancel = timer_cancel,
132 .timer_remove = timer_remove,
133
134 .watch_add = watch_add,
135 .watch_update_mask = watch_update_mask,
136 .watch_remove = watch_remove,
137 };
138
139 /* functions for the rest of qemu */
140
141 void qemu_spice_init(void)
142 {
143 QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
144 const char *password;
145 int port;
146
147 if (!opts) {
148 return;
149 }
150 port = qemu_opt_get_number(opts, "port", 0);
151 if (!port) {
152 return;
153 }
154 password = qemu_opt_get(opts, "password");
155
156 spice_server = spice_server_new();
157 spice_server_set_port(spice_server, port);
158 if (password) {
159 spice_server_set_ticket(spice_server, password, 0, 0, 0);
160 }
161 if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
162 spice_server_set_noauth(spice_server);
163 }
164
165 /* TODO: make configurable via cmdline */
166 spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
167
168 spice_server_init(spice_server, &core_interface);
169 using_spice = 1;
170 }
171
172 int qemu_spice_add_interface(SpiceBaseInstance *sin)
173 {
174 return spice_server_add_interface(spice_server, sin);
175 }
176
177 static void spice_register_config(void)
178 {
179 qemu_add_opts(&qemu_spice_opts);
180 }
181 machine_init(spice_register_config);
182
183 static void spice_initialize(void)
184 {
185 qemu_spice_init();
186 }
187 device_init(spice_initialize);