Disabling execution of cyclictest as part of verify job.
[kvmfornfv.git] / qemu / spice-qemu-char.c
1 #include "qemu/osdep.h"
2 #include "trace.h"
3 #include "ui/qemu-spice.h"
4 #include "sysemu/char.h"
5 #include <spice.h>
6 #include <spice/protocol.h>
7
8
9 typedef struct SpiceCharDriver {
10     CharDriverState*      chr;
11     SpiceCharDeviceInstance     sin;
12     bool                  active;
13     bool                  blocked;
14     const uint8_t         *datapos;
15     int                   datalen;
16     QLIST_ENTRY(SpiceCharDriver) next;
17 } SpiceCharDriver;
18
19 typedef struct SpiceCharSource {
20     GSource               source;
21     SpiceCharDriver       *scd;
22 } SpiceCharSource;
23
24 static QLIST_HEAD(, SpiceCharDriver) spice_chars =
25     QLIST_HEAD_INITIALIZER(spice_chars);
26
27 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
28 {
29     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
30     ssize_t out = 0;
31     ssize_t last_out;
32     uint8_t* p = (uint8_t*)buf;
33
34     while (len > 0) {
35         int can_write = qemu_chr_be_can_write(scd->chr);
36         last_out = MIN(len, can_write);
37         if (last_out <= 0) {
38             break;
39         }
40         qemu_chr_be_write(scd->chr, p, last_out);
41         out += last_out;
42         len -= last_out;
43         p += last_out;
44     }
45
46     trace_spice_vmc_write(out, len + out);
47     return out;
48 }
49
50 static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
51 {
52     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
53     int bytes = MIN(len, scd->datalen);
54
55     if (bytes > 0) {
56         memcpy(buf, scd->datapos, bytes);
57         scd->datapos += bytes;
58         scd->datalen -= bytes;
59         assert(scd->datalen >= 0);
60     }
61     if (scd->datalen == 0) {
62         scd->datapos = 0;
63         scd->blocked = false;
64     }
65     trace_spice_vmc_read(bytes, len);
66     return bytes;
67 }
68
69 #if SPICE_SERVER_VERSION >= 0x000c02
70 static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
71 {
72     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
73     int chr_event;
74
75     switch (event) {
76     case SPICE_PORT_EVENT_BREAK:
77         chr_event = CHR_EVENT_BREAK;
78         break;
79     default:
80         return;
81     }
82
83     trace_spice_vmc_event(chr_event);
84     qemu_chr_be_event(scd->chr, chr_event);
85 }
86 #endif
87
88 static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
89 {
90     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
91
92     if ((scd->chr->be_open && connected) ||
93         (!scd->chr->be_open && !connected)) {
94         return;
95     }
96
97     qemu_chr_be_event(scd->chr,
98                       connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
99 }
100
101 static SpiceCharDeviceInterface vmc_interface = {
102     .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
103     .base.description   = "spice virtual channel char device",
104     .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
105     .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
106     .state              = vmc_state,
107     .write              = vmc_write,
108     .read               = vmc_read,
109 #if SPICE_SERVER_VERSION >= 0x000c02
110     .event              = vmc_event,
111 #endif
112 #if SPICE_SERVER_VERSION >= 0x000c06
113     .flags              = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE,
114 #endif
115 };
116
117
118 static void vmc_register_interface(SpiceCharDriver *scd)
119 {
120     if (scd->active) {
121         return;
122     }
123     scd->sin.base.sif = &vmc_interface.base;
124     qemu_spice_add_interface(&scd->sin.base);
125     scd->active = true;
126     trace_spice_vmc_register_interface(scd);
127 }
128
129 static void vmc_unregister_interface(SpiceCharDriver *scd)
130 {
131     if (!scd->active) {
132         return;
133     }
134     spice_server_remove_interface(&scd->sin.base);
135     scd->active = false;
136     trace_spice_vmc_unregister_interface(scd);
137 }
138
139 static gboolean spice_char_source_prepare(GSource *source, gint *timeout)
140 {
141     SpiceCharSource *src = (SpiceCharSource *)source;
142
143     *timeout = -1;
144
145     return !src->scd->blocked;
146 }
147
148 static gboolean spice_char_source_check(GSource *source)
149 {
150     SpiceCharSource *src = (SpiceCharSource *)source;
151
152     return !src->scd->blocked;
153 }
154
155 static gboolean spice_char_source_dispatch(GSource *source,
156     GSourceFunc callback, gpointer user_data)
157 {
158     GIOFunc func = (GIOFunc)callback;
159
160     return func(NULL, G_IO_OUT, user_data);
161 }
162
163 static GSourceFuncs SpiceCharSourceFuncs = {
164     .prepare  = spice_char_source_prepare,
165     .check    = spice_char_source_check,
166     .dispatch = spice_char_source_dispatch,
167 };
168
169 static GSource *spice_chr_add_watch(CharDriverState *chr, GIOCondition cond)
170 {
171     SpiceCharDriver *scd = chr->opaque;
172     SpiceCharSource *src;
173
174     assert(cond & G_IO_OUT);
175
176     src = (SpiceCharSource *)g_source_new(&SpiceCharSourceFuncs,
177                                           sizeof(SpiceCharSource));
178     src->scd = scd;
179
180     return (GSource *)src;
181 }
182
183 static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
184 {
185     SpiceCharDriver *s = chr->opaque;
186     int read_bytes;
187
188     assert(s->datalen == 0);
189     s->datapos = buf;
190     s->datalen = len;
191     spice_server_char_device_wakeup(&s->sin);
192     read_bytes = len - s->datalen;
193     if (read_bytes != len) {
194         /* We'll get passed in the unconsumed data with the next call */
195         s->datalen = 0;
196         s->datapos = NULL;
197         s->blocked = true;
198     }
199     return read_bytes;
200 }
201
202 static void spice_chr_close(struct CharDriverState *chr)
203 {
204     SpiceCharDriver *s = chr->opaque;
205
206     vmc_unregister_interface(s);
207     QLIST_REMOVE(s, next);
208
209     g_free((char *)s->sin.subtype);
210 #if SPICE_SERVER_VERSION >= 0x000c02
211     g_free((char *)s->sin.portname);
212 #endif
213     g_free(s);
214 }
215
216 static void spice_vmc_set_fe_open(struct CharDriverState *chr, int fe_open)
217 {
218     SpiceCharDriver *s = chr->opaque;
219     if (fe_open) {
220         vmc_register_interface(s);
221     } else {
222         vmc_unregister_interface(s);
223     }
224 }
225
226 static void spice_port_set_fe_open(struct CharDriverState *chr, int fe_open)
227 {
228 #if SPICE_SERVER_VERSION >= 0x000c02
229     SpiceCharDriver *s = chr->opaque;
230
231     if (fe_open) {
232         spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
233     } else {
234         spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED);
235     }
236 #endif
237 }
238
239 static void spice_chr_fe_event(struct CharDriverState *chr, int event)
240 {
241 #if SPICE_SERVER_VERSION >= 0x000c02
242     SpiceCharDriver *s = chr->opaque;
243
244     spice_server_port_event(&s->sin, event);
245 #endif
246 }
247
248 static void print_allowed_subtypes(void)
249 {
250     const char** psubtype;
251     int i;
252
253     fprintf(stderr, "allowed names: ");
254     for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
255         *psubtype != NULL; ++psubtype, ++i) {
256         if (i == 0) {
257             fprintf(stderr, "%s", *psubtype);
258         } else {
259             fprintf(stderr, ", %s", *psubtype);
260         }
261     }
262     fprintf(stderr, "\n");
263 }
264
265 static void spice_chr_accept_input(struct CharDriverState *chr)
266 {
267     SpiceCharDriver *s = chr->opaque;
268
269     spice_server_char_device_wakeup(&s->sin);
270 }
271
272 static CharDriverState *chr_open(const char *subtype,
273                                  void (*set_fe_open)(struct CharDriverState *,
274                                                      int),
275                                  ChardevCommon *backend,
276                                  Error **errp)
277 {
278     CharDriverState *chr;
279     SpiceCharDriver *s;
280
281     chr = qemu_chr_alloc(backend, errp);
282     if (!chr) {
283         return NULL;
284     }
285     s = g_malloc0(sizeof(SpiceCharDriver));
286     s->chr = chr;
287     s->active = false;
288     s->sin.subtype = g_strdup(subtype);
289     chr->opaque = s;
290     chr->chr_write = spice_chr_write;
291     chr->chr_add_watch = spice_chr_add_watch;
292     chr->chr_close = spice_chr_close;
293     chr->chr_set_fe_open = set_fe_open;
294     chr->explicit_be_open = true;
295     chr->chr_fe_event = spice_chr_fe_event;
296     chr->chr_accept_input = spice_chr_accept_input;
297
298     QLIST_INSERT_HEAD(&spice_chars, s, next);
299
300     return chr;
301 }
302
303 static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
304                                                 ChardevBackend *backend,
305                                                 ChardevReturn *ret,
306                                                 Error **errp)
307 {
308     ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
309     const char *type = spicevmc->type;
310     const char **psubtype = spice_server_char_device_recognized_subtypes();
311     ChardevCommon *common = qapi_ChardevSpiceChannel_base(spicevmc);
312
313     for (; *psubtype != NULL; ++psubtype) {
314         if (strcmp(type, *psubtype) == 0) {
315             break;
316         }
317     }
318     if (*psubtype == NULL) {
319         fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
320         print_allowed_subtypes();
321         return NULL;
322     }
323
324     return chr_open(type, spice_vmc_set_fe_open, common, errp);
325 }
326
327 #if SPICE_SERVER_VERSION >= 0x000c02
328 static CharDriverState *qemu_chr_open_spice_port(const char *id,
329                                                  ChardevBackend *backend,
330                                                  ChardevReturn *ret,
331                                                  Error **errp)
332 {
333     ChardevSpicePort *spiceport = backend->u.spiceport.data;
334     const char *name = spiceport->fqdn;
335     ChardevCommon *common = qapi_ChardevSpicePort_base(spiceport);
336     CharDriverState *chr;
337     SpiceCharDriver *s;
338
339     if (name == NULL) {
340         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
341         return NULL;
342     }
343
344     chr = chr_open("port", spice_port_set_fe_open, common, errp);
345     if (!chr) {
346         return NULL;
347     }
348     s = chr->opaque;
349     s->sin.portname = g_strdup(name);
350
351     return chr;
352 }
353
354 void qemu_spice_register_ports(void)
355 {
356     SpiceCharDriver *s;
357
358     QLIST_FOREACH(s, &spice_chars, next) {
359         if (s->sin.portname == NULL) {
360             continue;
361         }
362         vmc_register_interface(s);
363     }
364 }
365 #endif
366
367 static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
368                                      Error **errp)
369 {
370     const char *name = qemu_opt_get(opts, "name");
371     ChardevSpiceChannel *spicevmc;
372
373     if (name == NULL) {
374         error_setg(errp, "chardev: spice channel: no name given");
375         return;
376     }
377     spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1);
378     qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc));
379     spicevmc->type = g_strdup(name);
380 }
381
382 static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
383                                       Error **errp)
384 {
385     const char *name = qemu_opt_get(opts, "name");
386     ChardevSpicePort *spiceport;
387
388     if (name == NULL) {
389         error_setg(errp, "chardev: spice port: no name given");
390         return;
391     }
392     spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1);
393     qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport));
394     spiceport->fqdn = g_strdup(name);
395 }
396
397 static void register_types(void)
398 {
399     register_char_driver("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC,
400                          qemu_chr_parse_spice_vmc, qemu_chr_open_spice_vmc);
401     register_char_driver("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT,
402                          qemu_chr_parse_spice_port, qemu_chr_open_spice_port);
403 }
404
405 type_init(register_types);