9pfs: add cleanup operation in FileOperations
[sdk/emulator/qemu.git] / 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_free(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 print_allowed_subtypes(void)
240 {
241     const char** psubtype;
242     int i;
243
244     fprintf(stderr, "allowed names: ");
245     for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
246         *psubtype != NULL; ++psubtype, ++i) {
247         if (i == 0) {
248             fprintf(stderr, "%s", *psubtype);
249         } else {
250             fprintf(stderr, ", %s", *psubtype);
251         }
252     }
253     fprintf(stderr, "\n");
254 }
255
256 static void spice_chr_accept_input(struct CharDriverState *chr)
257 {
258     SpiceCharDriver *s = chr->opaque;
259
260     spice_server_char_device_wakeup(&s->sin);
261 }
262
263 static CharDriverState *chr_open(const char *subtype,
264                                  void (*set_fe_open)(struct CharDriverState *,
265                                                      int),
266                                  ChardevCommon *backend,
267                                  Error **errp)
268 {
269     CharDriverState *chr;
270     SpiceCharDriver *s;
271
272     chr = qemu_chr_alloc(backend, errp);
273     if (!chr) {
274         return NULL;
275     }
276     s = g_malloc0(sizeof(SpiceCharDriver));
277     s->chr = chr;
278     s->active = false;
279     s->sin.subtype = g_strdup(subtype);
280     chr->opaque = s;
281     chr->chr_write = spice_chr_write;
282     chr->chr_add_watch = spice_chr_add_watch;
283     chr->chr_free = spice_chr_free;
284     chr->chr_set_fe_open = set_fe_open;
285     chr->chr_accept_input = spice_chr_accept_input;
286
287     QLIST_INSERT_HEAD(&spice_chars, s, next);
288
289     return chr;
290 }
291
292 static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
293                                                 ChardevBackend *backend,
294                                                 ChardevReturn *ret,
295                                                 bool *be_opened,
296                                                 Error **errp)
297 {
298     ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
299     const char *type = spicevmc->type;
300     const char **psubtype = spice_server_char_device_recognized_subtypes();
301     ChardevCommon *common = qapi_ChardevSpiceChannel_base(spicevmc);
302
303     for (; *psubtype != NULL; ++psubtype) {
304         if (strcmp(type, *psubtype) == 0) {
305             break;
306         }
307     }
308     if (*psubtype == NULL) {
309         fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type);
310         print_allowed_subtypes();
311         return NULL;
312     }
313
314     *be_opened = false;
315     return chr_open(type, spice_vmc_set_fe_open, common, errp);
316 }
317
318 #if SPICE_SERVER_VERSION >= 0x000c02
319 static CharDriverState *qemu_chr_open_spice_port(const char *id,
320                                                  ChardevBackend *backend,
321                                                  ChardevReturn *ret,
322                                                  bool *be_opened,
323                                                  Error **errp)
324 {
325     ChardevSpicePort *spiceport = backend->u.spiceport.data;
326     const char *name = spiceport->fqdn;
327     ChardevCommon *common = qapi_ChardevSpicePort_base(spiceport);
328     CharDriverState *chr;
329     SpiceCharDriver *s;
330
331     if (name == NULL) {
332         fprintf(stderr, "spice-qemu-char: missing name parameter\n");
333         return NULL;
334     }
335
336     chr = chr_open("port", spice_port_set_fe_open, common, errp);
337     if (!chr) {
338         return NULL;
339     }
340     *be_opened = false;
341     s = chr->opaque;
342     s->sin.portname = g_strdup(name);
343
344     return chr;
345 }
346
347 void qemu_spice_register_ports(void)
348 {
349     SpiceCharDriver *s;
350
351     QLIST_FOREACH(s, &spice_chars, next) {
352         if (s->sin.portname == NULL) {
353             continue;
354         }
355         vmc_register_interface(s);
356     }
357 }
358 #endif
359
360 static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
361                                      Error **errp)
362 {
363     const char *name = qemu_opt_get(opts, "name");
364     ChardevSpiceChannel *spicevmc;
365
366     if (name == NULL) {
367         error_setg(errp, "chardev: spice channel: no name given");
368         return;
369     }
370     spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1);
371     qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc));
372     spicevmc->type = g_strdup(name);
373 }
374
375 static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
376                                       Error **errp)
377 {
378     const char *name = qemu_opt_get(opts, "name");
379     ChardevSpicePort *spiceport;
380
381     if (name == NULL) {
382         error_setg(errp, "chardev: spice port: no name given");
383         return;
384     }
385     spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1);
386     qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport));
387     spiceport->fqdn = g_strdup(name);
388 }
389
390 static void register_types(void)
391 {
392     register_char_driver("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC,
393                          qemu_chr_parse_spice_vmc, qemu_chr_open_spice_vmc);
394     register_char_driver("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT,
395                          qemu_chr_parse_spice_port, qemu_chr_open_spice_port);
396 }
397
398 type_init(register_types);