|
|
1.1 root 1: #include "config-host.h"
2: #include "trace.h"
3: #include "ui/qemu-spice.h"
4: #include <spice.h>
5: #include <spice-experimental.h>
6:
7: #include "osdep.h"
8:
9: #define dprintf(_scd, _level, _fmt, ...) \
10: do { \
11: static unsigned __dprintf_counter = 0; \
12: if (_scd->debug >= _level) { \
13: fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
14: } \
15: } while (0)
16:
17: #define VMC_MAX_HOST_WRITE 2048
18:
19: typedef struct SpiceCharDriver {
20: CharDriverState* chr;
21: SpiceCharDeviceInstance sin;
22: char *subtype;
23: bool active;
24: uint8_t *buffer;
25: uint8_t *datapos;
26: ssize_t bufsize, datalen;
27: uint32_t debug;
28: } SpiceCharDriver;
29:
30: static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
31: {
32: SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
33: ssize_t out = 0;
34: ssize_t last_out;
35: uint8_t* p = (uint8_t*)buf;
36:
37: while (len > 0) {
38: last_out = MIN(len, VMC_MAX_HOST_WRITE);
1.1.1.3 root 39: if (qemu_chr_be_can_write(scd->chr) < last_out) {
1.1 root 40: break;
41: }
1.1.1.3 root 42: qemu_chr_be_write(scd->chr, p, last_out);
1.1.1.2 root 43: out += last_out;
44: len -= last_out;
45: p += last_out;
1.1 root 46: }
47:
1.1.1.3 root 48: dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out);
1.1 root 49: trace_spice_vmc_write(out, len + out);
50: return out;
51: }
52:
53: static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
54: {
55: SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
56: int bytes = MIN(len, scd->datalen);
57:
58: dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
59: if (bytes > 0) {
60: memcpy(buf, scd->datapos, bytes);
61: scd->datapos += bytes;
62: scd->datalen -= bytes;
63: assert(scd->datalen >= 0);
64: if (scd->datalen == 0) {
65: scd->datapos = 0;
66: }
67: }
68: trace_spice_vmc_read(bytes, len);
69: return bytes;
70: }
71:
1.1.1.3 root 72: static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
73: {
74: SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
75:
76: #if SPICE_SERVER_VERSION < 0x000901
77: /*
78: * spice-server calls the state callback for the agent channel when the
79: * spice client connects / disconnects. Given that not the client but
80: * the server is doing the parsing of the messages this is wrong as the
81: * server is still listening. Worse, this causes the parser in the server
82: * to go out of sync, so we ignore state calls for subtype vdagent
83: * spicevmc chardevs. For the full story see:
84: * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
85: */
86: if (strcmp(sin->subtype, "vdagent") == 0) {
87: return;
88: }
89: #endif
90:
91: if ((scd->chr->opened && connected) ||
92: (!scd->chr->opened && !connected)) {
93: return;
94: }
95:
96: qemu_chr_be_event(scd->chr,
97: connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
98: }
99:
1.1 root 100: static SpiceCharDeviceInterface vmc_interface = {
101: .base.type = SPICE_INTERFACE_CHAR_DEVICE,
102: .base.description = "spice virtual channel char device",
103: .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
104: .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
1.1.1.3 root 105: .state = vmc_state,
1.1 root 106: .write = vmc_write,
107: .read = vmc_read,
108: };
109:
110:
111: static void vmc_register_interface(SpiceCharDriver *scd)
112: {
113: if (scd->active) {
114: return;
115: }
116: dprintf(scd, 1, "%s\n", __func__);
117: scd->sin.base.sif = &vmc_interface.base;
118: qemu_spice_add_interface(&scd->sin.base);
119: scd->active = true;
120: trace_spice_vmc_register_interface(scd);
121: }
122:
123: static void vmc_unregister_interface(SpiceCharDriver *scd)
124: {
125: if (!scd->active) {
126: return;
127: }
128: dprintf(scd, 1, "%s\n", __func__);
129: spice_server_remove_interface(&scd->sin.base);
130: scd->active = false;
131: trace_spice_vmc_unregister_interface(scd);
132: }
133:
134:
135: static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
136: {
137: SpiceCharDriver *s = chr->opaque;
138:
139: dprintf(s, 2, "%s: %d\n", __func__, len);
140: vmc_register_interface(s);
141: assert(s->datalen == 0);
142: if (s->bufsize < len) {
143: s->bufsize = len;
1.1.1.3 root 144: s->buffer = g_realloc(s->buffer, s->bufsize);
1.1 root 145: }
146: memcpy(s->buffer, buf, len);
147: s->datapos = s->buffer;
148: s->datalen = len;
149: spice_server_char_device_wakeup(&s->sin);
150: return len;
151: }
152:
153: static void spice_chr_close(struct CharDriverState *chr)
154: {
155: SpiceCharDriver *s = chr->opaque;
156:
157: printf("%s\n", __func__);
158: vmc_unregister_interface(s);
1.1.1.3 root 159: g_free(s);
1.1 root 160: }
161:
1.1.1.2 root 162: static void spice_chr_guest_open(struct CharDriverState *chr)
163: {
164: SpiceCharDriver *s = chr->opaque;
165: vmc_register_interface(s);
166: }
167:
168: static void spice_chr_guest_close(struct CharDriverState *chr)
169: {
170: SpiceCharDriver *s = chr->opaque;
171: vmc_unregister_interface(s);
172: }
173:
1.1 root 174: static void print_allowed_subtypes(void)
175: {
176: const char** psubtype;
177: int i;
178:
179: fprintf(stderr, "allowed names: ");
180: for(i=0, psubtype = spice_server_char_device_recognized_subtypes();
181: *psubtype != NULL; ++psubtype, ++i) {
182: if (i == 0) {
183: fprintf(stderr, "%s", *psubtype);
184: } else {
185: fprintf(stderr, ", %s", *psubtype);
186: }
187: }
188: fprintf(stderr, "\n");
189: }
190:
1.1.1.4 ! root 191: CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
1.1 root 192: {
193: CharDriverState *chr;
194: SpiceCharDriver *s;
195: const char* name = qemu_opt_get(opts, "name");
196: uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
197: const char** psubtype = spice_server_char_device_recognized_subtypes();
198: const char *subtype = NULL;
199:
200: if (name == NULL) {
201: fprintf(stderr, "spice-qemu-char: missing name parameter\n");
202: print_allowed_subtypes();
1.1.1.4 ! root 203: return NULL;
1.1 root 204: }
205: for(;*psubtype != NULL; ++psubtype) {
206: if (strcmp(name, *psubtype) == 0) {
207: subtype = *psubtype;
208: break;
209: }
210: }
211: if (subtype == NULL) {
1.1.1.4 ! root 212: fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name);
1.1 root 213: print_allowed_subtypes();
1.1.1.4 ! root 214: return NULL;
1.1 root 215: }
216:
1.1.1.3 root 217: chr = g_malloc0(sizeof(CharDriverState));
218: s = g_malloc0(sizeof(SpiceCharDriver));
1.1 root 219: s->chr = chr;
220: s->debug = debug;
221: s->active = false;
222: s->sin.subtype = subtype;
223: chr->opaque = s;
224: chr->chr_write = spice_chr_write;
225: chr->chr_close = spice_chr_close;
1.1.1.2 root 226: chr->chr_guest_open = spice_chr_guest_open;
227: chr->chr_guest_close = spice_chr_guest_close;
1.1 root 228:
1.1.1.3 root 229: #if SPICE_SERVER_VERSION < 0x000901
230: /* See comment in vmc_state() */
231: if (strcmp(subtype, "vdagent") == 0) {
232: qemu_chr_generic_open(chr);
233: }
234: #endif
1.1 root 235:
1.1.1.4 ! root 236: return chr;
1.1 root 237: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.