qemu-file-unix.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * QEMU System Emulator
  3. *
  4. * Copyright (c) 2003-2008 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu-common.h"
  25. #include "qemu/iov.h"
  26. #include "qemu/sockets.h"
  27. #include "block/coroutine.h"
  28. #include "migration/qemu-file.h"
  29. #include "migration/qemu-file-internal.h"
  30. typedef struct QEMUFileSocket {
  31. int fd;
  32. QEMUFile *file;
  33. } QEMUFileSocket;
  34. static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
  35. int64_t pos)
  36. {
  37. QEMUFileSocket *s = opaque;
  38. ssize_t len;
  39. ssize_t size = iov_size(iov, iovcnt);
  40. len = iov_send(s->fd, iov, iovcnt, 0, size);
  41. if (len < size) {
  42. len = -socket_error();
  43. }
  44. return len;
  45. }
  46. static int socket_get_fd(void *opaque)
  47. {
  48. QEMUFileSocket *s = opaque;
  49. return s->fd;
  50. }
  51. static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
  52. size_t size)
  53. {
  54. QEMUFileSocket *s = opaque;
  55. ssize_t len;
  56. for (;;) {
  57. len = qemu_recv(s->fd, buf, size, 0);
  58. if (len != -1) {
  59. break;
  60. }
  61. if (socket_error() == EAGAIN) {
  62. yield_until_fd_readable(s->fd);
  63. } else if (socket_error() != EINTR) {
  64. break;
  65. }
  66. }
  67. if (len == -1) {
  68. len = -socket_error();
  69. }
  70. return len;
  71. }
  72. static int socket_close(void *opaque)
  73. {
  74. QEMUFileSocket *s = opaque;
  75. closesocket(s->fd);
  76. g_free(s);
  77. return 0;
  78. }
  79. static int socket_shutdown(void *opaque, bool rd, bool wr)
  80. {
  81. QEMUFileSocket *s = opaque;
  82. if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
  83. return -errno;
  84. } else {
  85. return 0;
  86. }
  87. }
  88. static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
  89. int64_t pos)
  90. {
  91. QEMUFileSocket *s = opaque;
  92. ssize_t len, offset;
  93. ssize_t size = iov_size(iov, iovcnt);
  94. ssize_t total = 0;
  95. assert(iovcnt > 0);
  96. offset = 0;
  97. while (size > 0) {
  98. /* Find the next start position; skip all full-sized vector elements */
  99. while (offset >= iov[0].iov_len) {
  100. offset -= iov[0].iov_len;
  101. iov++, iovcnt--;
  102. }
  103. /* skip `offset' bytes from the (now) first element, undo it on exit */
  104. assert(iovcnt > 0);
  105. iov[0].iov_base += offset;
  106. iov[0].iov_len -= offset;
  107. do {
  108. len = writev(s->fd, iov, iovcnt);
  109. } while (len == -1 && errno == EINTR);
  110. if (len == -1) {
  111. return -errno;
  112. }
  113. /* Undo the changes above */
  114. iov[0].iov_base -= offset;
  115. iov[0].iov_len += offset;
  116. /* Prepare for the next iteration */
  117. offset += len;
  118. total += len;
  119. size -= len;
  120. }
  121. return total;
  122. }
  123. static ssize_t unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
  124. size_t size)
  125. {
  126. QEMUFileSocket *s = opaque;
  127. ssize_t len;
  128. for (;;) {
  129. len = read(s->fd, buf, size);
  130. if (len != -1) {
  131. break;
  132. }
  133. if (errno == EAGAIN) {
  134. yield_until_fd_readable(s->fd);
  135. } else if (errno != EINTR) {
  136. break;
  137. }
  138. }
  139. if (len == -1) {
  140. len = -errno;
  141. }
  142. return len;
  143. }
  144. static int unix_close(void *opaque)
  145. {
  146. QEMUFileSocket *s = opaque;
  147. close(s->fd);
  148. g_free(s);
  149. return 0;
  150. }
  151. static const QEMUFileOps unix_read_ops = {
  152. .get_fd = socket_get_fd,
  153. .get_buffer = unix_get_buffer,
  154. .close = unix_close
  155. };
  156. static const QEMUFileOps unix_write_ops = {
  157. .get_fd = socket_get_fd,
  158. .writev_buffer = unix_writev_buffer,
  159. .close = unix_close
  160. };
  161. QEMUFile *qemu_fdopen(int fd, const char *mode)
  162. {
  163. QEMUFileSocket *s;
  164. if (mode == NULL ||
  165. (mode[0] != 'r' && mode[0] != 'w') ||
  166. mode[1] != 'b' || mode[2] != 0) {
  167. fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
  168. return NULL;
  169. }
  170. s = g_malloc0(sizeof(QEMUFileSocket));
  171. s->fd = fd;
  172. if (mode[0] == 'r') {
  173. s->file = qemu_fopen_ops(s, &unix_read_ops);
  174. } else {
  175. s->file = qemu_fopen_ops(s, &unix_write_ops);
  176. }
  177. return s->file;
  178. }
  179. static const QEMUFileOps socket_read_ops = {
  180. .get_fd = socket_get_fd,
  181. .get_buffer = socket_get_buffer,
  182. .close = socket_close,
  183. .shut_down = socket_shutdown
  184. };
  185. static const QEMUFileOps socket_write_ops = {
  186. .get_fd = socket_get_fd,
  187. .writev_buffer = socket_writev_buffer,
  188. .close = socket_close,
  189. .shut_down = socket_shutdown
  190. };
  191. QEMUFile *qemu_fopen_socket(int fd, const char *mode)
  192. {
  193. QEMUFileSocket *s;
  194. if (qemu_file_mode_is_not_valid(mode)) {
  195. return NULL;
  196. }
  197. s = g_malloc0(sizeof(QEMUFileSocket));
  198. s->fd = fd;
  199. if (mode[0] == 'w') {
  200. qemu_set_block(s->fd);
  201. s->file = qemu_fopen_ops(s, &socket_write_ops);
  202. } else {
  203. s->file = qemu_fopen_ops(s, &socket_read_ops);
  204. }
  205. return s->file;
  206. }