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