2
0

spice-qemu-char.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #include "config-host.h"
  2. #include "trace.h"
  3. #include "ui/qemu-spice.h"
  4. #include "char/char.h"
  5. #include <spice.h>
  6. #include <spice-experimental.h>
  7. #include <spice/protocol.h>
  8. #include "qemu/osdep.h"
  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. typedef struct SpiceCharDriver {
  17. CharDriverState* chr;
  18. SpiceCharDeviceInstance sin;
  19. char *subtype;
  20. bool active;
  21. uint8_t *buffer;
  22. uint8_t *datapos;
  23. ssize_t bufsize, datalen;
  24. uint32_t debug;
  25. QLIST_ENTRY(SpiceCharDriver) next;
  26. } SpiceCharDriver;
  27. static QLIST_HEAD(, SpiceCharDriver) spice_chars =
  28. QLIST_HEAD_INITIALIZER(spice_chars);
  29. static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
  30. {
  31. SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
  32. ssize_t out = 0;
  33. ssize_t last_out;
  34. uint8_t* p = (uint8_t*)buf;
  35. while (len > 0) {
  36. last_out = MIN(len, qemu_chr_be_can_write(scd->chr));
  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. dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out);
  46. trace_spice_vmc_write(out, len + out);
  47. return out;
  48. }
  49. static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
  50. {
  51. SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
  52. int bytes = MIN(len, scd->datalen);
  53. dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen);
  54. if (bytes > 0) {
  55. memcpy(buf, scd->datapos, bytes);
  56. scd->datapos += bytes;
  57. scd->datalen -= bytes;
  58. assert(scd->datalen >= 0);
  59. if (scd->datalen == 0) {
  60. scd->datapos = 0;
  61. }
  62. }
  63. trace_spice_vmc_read(bytes, len);
  64. return bytes;
  65. }
  66. #if SPICE_SERVER_VERSION >= 0x000c02
  67. static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
  68. {
  69. SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
  70. int chr_event;
  71. switch (event) {
  72. case SPICE_PORT_EVENT_BREAK:
  73. chr_event = CHR_EVENT_BREAK;
  74. break;
  75. default:
  76. dprintf(scd, 2, "%s: unknown %d\n", __func__, event);
  77. return;
  78. }
  79. dprintf(scd, 2, "%s: %d\n", __func__, event);
  80. trace_spice_vmc_event(chr_event);
  81. qemu_chr_be_event(scd->chr, chr_event);
  82. }
  83. #endif
  84. static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
  85. {
  86. SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
  87. #if SPICE_SERVER_VERSION < 0x000901
  88. /*
  89. * spice-server calls the state callback for the agent channel when the
  90. * spice client connects / disconnects. Given that not the client but
  91. * the server is doing the parsing of the messages this is wrong as the
  92. * server is still listening. Worse, this causes the parser in the server
  93. * to go out of sync, so we ignore state calls for subtype vdagent
  94. * spicevmc chardevs. For the full story see:
  95. * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html
  96. */
  97. if (strcmp(sin->subtype, "vdagent") == 0) {
  98. return;
  99. }
  100. #endif
  101. if ((scd->chr->opened && connected) ||
  102. (!scd->chr->opened && !connected)) {
  103. return;
  104. }
  105. qemu_chr_be_event(scd->chr,
  106. connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
  107. }
  108. static SpiceCharDeviceInterface vmc_interface = {
  109. .base.type = SPICE_INTERFACE_CHAR_DEVICE,
  110. .base.description = "spice virtual channel char device",
  111. .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
  112. .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
  113. .state = vmc_state,
  114. .write = vmc_write,
  115. .read = vmc_read,
  116. #if SPICE_SERVER_VERSION >= 0x000c02
  117. .event = vmc_event,
  118. #endif
  119. };
  120. static void vmc_register_interface(SpiceCharDriver *scd)
  121. {
  122. if (scd->active) {
  123. return;
  124. }
  125. dprintf(scd, 1, "%s\n", __func__);
  126. scd->sin.base.sif = &vmc_interface.base;
  127. qemu_spice_add_interface(&scd->sin.base);
  128. scd->active = true;
  129. trace_spice_vmc_register_interface(scd);
  130. }
  131. static void vmc_unregister_interface(SpiceCharDriver *scd)
  132. {
  133. if (!scd->active) {
  134. return;
  135. }
  136. dprintf(scd, 1, "%s\n", __func__);
  137. spice_server_remove_interface(&scd->sin.base);
  138. scd->active = false;
  139. trace_spice_vmc_unregister_interface(scd);
  140. }
  141. static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
  142. {
  143. SpiceCharDriver *s = chr->opaque;
  144. dprintf(s, 2, "%s: %d\n", __func__, len);
  145. vmc_register_interface(s);
  146. assert(s->datalen == 0);
  147. if (s->bufsize < len) {
  148. s->bufsize = len;
  149. s->buffer = g_realloc(s->buffer, s->bufsize);
  150. }
  151. memcpy(s->buffer, buf, len);
  152. s->datapos = s->buffer;
  153. s->datalen = len;
  154. spice_server_char_device_wakeup(&s->sin);
  155. return len;
  156. }
  157. static void spice_chr_close(struct CharDriverState *chr)
  158. {
  159. SpiceCharDriver *s = chr->opaque;
  160. printf("%s\n", __func__);
  161. vmc_unregister_interface(s);
  162. QLIST_REMOVE(s, next);
  163. g_free(s);
  164. }
  165. static void spice_chr_guest_open(struct CharDriverState *chr)
  166. {
  167. SpiceCharDriver *s = chr->opaque;
  168. vmc_register_interface(s);
  169. }
  170. static void spice_chr_guest_close(struct CharDriverState *chr)
  171. {
  172. SpiceCharDriver *s = chr->opaque;
  173. vmc_unregister_interface(s);
  174. }
  175. static void print_allowed_subtypes(void)
  176. {
  177. const char** psubtype;
  178. int i;
  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. static CharDriverState *chr_open(QemuOpts *opts, const char *subtype)
  191. {
  192. CharDriverState *chr;
  193. SpiceCharDriver *s;
  194. uint32_t debug = qemu_opt_get_number(opts, "debug", 0);
  195. chr = g_malloc0(sizeof(CharDriverState));
  196. s = g_malloc0(sizeof(SpiceCharDriver));
  197. s->chr = chr;
  198. s->debug = debug;
  199. s->active = false;
  200. s->sin.subtype = subtype;
  201. chr->opaque = s;
  202. chr->chr_write = spice_chr_write;
  203. chr->chr_close = spice_chr_close;
  204. chr->chr_guest_open = spice_chr_guest_open;
  205. chr->chr_guest_close = spice_chr_guest_close;
  206. QLIST_INSERT_HEAD(&spice_chars, s, next);
  207. return chr;
  208. }
  209. CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
  210. {
  211. CharDriverState *chr;
  212. const char *name = qemu_opt_get(opts, "name");
  213. const char **psubtype = spice_server_char_device_recognized_subtypes();
  214. const char *subtype = NULL;
  215. if (name == NULL) {
  216. fprintf(stderr, "spice-qemu-char: missing name parameter\n");
  217. print_allowed_subtypes();
  218. return NULL;
  219. }
  220. for(;*psubtype != NULL; ++psubtype) {
  221. if (strcmp(name, *psubtype) == 0) {
  222. subtype = *psubtype;
  223. break;
  224. }
  225. }
  226. if (subtype == NULL) {
  227. fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name);
  228. print_allowed_subtypes();
  229. return NULL;
  230. }
  231. chr = chr_open(opts, subtype);
  232. #if SPICE_SERVER_VERSION < 0x000901
  233. /* See comment in vmc_state() */
  234. if (strcmp(subtype, "vdagent") == 0) {
  235. qemu_chr_generic_open(chr);
  236. }
  237. #endif
  238. return chr;
  239. }
  240. #if SPICE_SERVER_VERSION >= 0x000c02
  241. CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts)
  242. {
  243. CharDriverState *chr;
  244. SpiceCharDriver *s;
  245. const char *name = qemu_opt_get(opts, "name");
  246. if (name == NULL) {
  247. fprintf(stderr, "spice-qemu-char: missing name parameter\n");
  248. return NULL;
  249. }
  250. chr = chr_open(opts, "port");
  251. s = chr->opaque;
  252. s->sin.portname = name;
  253. return chr;
  254. }
  255. void qemu_spice_register_ports(void)
  256. {
  257. SpiceCharDriver *s;
  258. QLIST_FOREACH(s, &spice_chars, next) {
  259. if (s->sin.portname == NULL) {
  260. continue;
  261. }
  262. vmc_register_interface(s);
  263. }
  264. }
  265. #endif