aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs2
-rw-r--r--qemu-config.c18
-rw-r--r--qemu-config.h1
-rw-r--r--qemu-options.hx21
-rw-r--r--ui/qemu-spice.h39
-rw-r--r--ui/spice-core.c187
-rw-r--r--vl.c14
7 files changed, 282 insertions, 0 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 8268574..2b58109 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -88,6 +88,8 @@ common-obj-y += pflib.o
common-obj-$(CONFIG_BRLAPI) += baum.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
+common-obj-$(CONFIG_SPICE) += ui/spice-core.o
+
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o
diff --git a/qemu-config.c b/qemu-config.c
index e3b746c..5c6ae63 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -351,6 +351,24 @@ static QemuOptsList qemu_cpudef_opts = {
},
};
+QemuOptsList qemu_spice_opts = {
+ .name = "spice",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
+ .desc = {
+ {
+ .name = "port",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "password",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "disable-ticketing",
+ .type = QEMU_OPT_BOOL,
+ },
+ { /* end if list */ }
+ },
+};
+
static QemuOptsList *vm_config_groups[32] = {
&qemu_drive_opts,
&qemu_chardev_opts,
diff --git a/qemu-config.h b/qemu-config.h
index 533a049..20d707f 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -3,6 +3,7 @@
extern QemuOptsList qemu_fsdev_opts;
extern QemuOptsList qemu_virtfs_opts;
+extern QemuOptsList qemu_spice_opts;
QemuOptsList *qemu_find_opts(const char *group);
void qemu_add_opts(QemuOptsList *list);
diff --git a/qemu-options.hx b/qemu-options.hx
index a0b5ae9..718d47a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -670,6 +670,27 @@ STEXI
Enable SDL.
ETEXI
+DEF("spice", HAS_ARG, QEMU_OPTION_spice,
+ "-spice <args> enable spice\n", QEMU_ARCH_ALL)
+STEXI
+@item -spice @var{option}[,@var{option}[,...]]
+@findex -spice
+Enable the spice remote desktop protocol. Valid options are
+
+@table @option
+
+@item port=<nr>
+Set the TCP port spice is listening on.
+
+@item password=<secret>
+Set the password you need to authenticate.
+
+@item disable-ticketing
+Allow client connects without authentication.
+
+@end table
+ETEXI
+
DEF("portrait", 0, QEMU_OPTION_portrait,
"-portrait rotate graphical output 90 deg left (only PXA LCD)\n",
QEMU_ARCH_ALL)
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
new file mode 100644
index 0000000..50faefb
--- /dev/null
+++ b/ui/qemu-spice.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_SPICE_H
+#define QEMU_SPICE_H
+
+#ifdef CONFIG_SPICE
+
+#include <spice.h>
+
+#include "qemu-option.h"
+#include "qemu-config.h"
+
+extern int using_spice;
+
+void qemu_spice_init(void);
+int qemu_spice_add_interface(SpiceBaseInstance *sin);
+
+#else /* CONFIG_SPICE */
+
+#define using_spice 0
+
+#endif /* CONFIG_SPICE */
+
+#endif /* QEMU_SPICE_H */
diff --git a/ui/spice-core.c b/ui/spice-core.c
new file mode 100644
index 0000000..006604b
--- /dev/null
+++ b/ui/spice-core.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <spice.h>
+#include <spice-experimental.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+
+/* core bits */
+
+static SpiceServer *spice_server;
+int using_spice = 0;
+
+struct SpiceTimer {
+ QEMUTimer *timer;
+ QTAILQ_ENTRY(SpiceTimer) next;
+};
+static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
+
+static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
+{
+ SpiceTimer *timer;
+
+ timer = qemu_mallocz(sizeof(*timer));
+ timer->timer = qemu_new_timer(rt_clock, func, opaque);
+ QTAILQ_INSERT_TAIL(&timers, timer, next);
+ return timer;
+}
+
+static void timer_start(SpiceTimer *timer, uint32_t ms)
+{
+ qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms);
+}
+
+static void timer_cancel(SpiceTimer *timer)
+{
+ qemu_del_timer(timer->timer);
+}
+
+static void timer_remove(SpiceTimer *timer)
+{
+ qemu_del_timer(timer->timer);
+ qemu_free_timer(timer->timer);
+ QTAILQ_REMOVE(&timers, timer, next);
+ qemu_free(timer);
+}
+
+struct SpiceWatch {
+ int fd;
+ int event_mask;
+ SpiceWatchFunc func;
+ void *opaque;
+ QTAILQ_ENTRY(SpiceWatch) next;
+};
+static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches);
+
+static void watch_read(void *opaque)
+{
+ SpiceWatch *watch = opaque;
+ watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
+}
+
+static void watch_write(void *opaque)
+{
+ SpiceWatch *watch = opaque;
+ watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
+}
+
+static void watch_update_mask(SpiceWatch *watch, int event_mask)
+{
+ IOHandler *on_read = NULL;
+ IOHandler *on_write = NULL;
+
+ watch->event_mask = event_mask;
+ if (watch->event_mask & SPICE_WATCH_EVENT_READ) {
+ on_read = watch_read;
+ }
+ if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) {
+ on_read = watch_write;
+ }
+ qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
+}
+
+static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+{
+ SpiceWatch *watch;
+
+ watch = qemu_mallocz(sizeof(*watch));
+ watch->fd = fd;
+ watch->func = func;
+ watch->opaque = opaque;
+ QTAILQ_INSERT_TAIL(&watches, watch, next);
+
+ watch_update_mask(watch, event_mask);
+ return watch;
+}
+
+static void watch_remove(SpiceWatch *watch)
+{
+ watch_update_mask(watch, 0);
+ QTAILQ_REMOVE(&watches, watch, next);
+ qemu_free(watch);
+}
+
+static SpiceCoreInterface core_interface = {
+ .base.type = SPICE_INTERFACE_CORE,
+ .base.description = "qemu core services",
+ .base.major_version = SPICE_INTERFACE_CORE_MAJOR,
+ .base.minor_version = SPICE_INTERFACE_CORE_MINOR,
+
+ .timer_add = timer_add,
+ .timer_start = timer_start,
+ .timer_cancel = timer_cancel,
+ .timer_remove = timer_remove,
+
+ .watch_add = watch_add,
+ .watch_update_mask = watch_update_mask,
+ .watch_remove = watch_remove,
+};
+
+/* functions for the rest of qemu */
+
+void qemu_spice_init(void)
+{
+ QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+ const char *password;
+ int port;
+
+ if (!opts) {
+ return;
+ }
+ port = qemu_opt_get_number(opts, "port", 0);
+ if (!port) {
+ return;
+ }
+ password = qemu_opt_get(opts, "password");
+
+ spice_server = spice_server_new();
+ spice_server_set_port(spice_server, port);
+ if (password) {
+ spice_server_set_ticket(spice_server, password, 0, 0, 0);
+ }
+ if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
+ spice_server_set_noauth(spice_server);
+ }
+
+ /* TODO: make configurable via cmdline */
+ spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+
+ spice_server_init(spice_server, &core_interface);
+ using_spice = 1;
+}
+
+int qemu_spice_add_interface(SpiceBaseInstance *sin)
+{
+ return spice_server_add_interface(spice_server, sin);
+}
+
+static void spice_register_config(void)
+{
+ qemu_add_opts(&qemu_spice_opts);
+}
+machine_init(spice_register_config);
+
+static void spice_initialize(void)
+{
+ qemu_spice_init();
+}
+device_init(spice_initialize);
diff --git a/vl.c b/vl.c
index 2edc853..27d9392 100644
--- a/vl.c
+++ b/vl.c
@@ -165,6 +165,8 @@ int main(int argc, char **argv)
#include "cpus.h"
#include "arch_init.h"
+#include "ui/qemu-spice.h"
+
//#define DEBUG_NET
//#define DEBUG_SLIRP
@@ -2616,6 +2618,18 @@ int main(int argc, char **argv, char **envp)
}
break;
}
+ case QEMU_OPTION_spice:
+ olist = qemu_find_opts("spice");
+ if (!olist) {
+ fprintf(stderr, "spice is not supported by this qemu build.\n");
+ exit(1);
+ }
+ opts = qemu_opts_parse(olist, optarg, 0);
+ if (!opts) {
+ fprintf(stderr, "parse error: %s\n", optarg);
+ exit(1);
+ }
+ break;
case QEMU_OPTION_writeconfig:
{
FILE *fp;