2
0

spice-qemu-char.c 6.8 KB

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