migration: convert unix socket protocol to use QIOChannel
[qemu.git] / migration / qemu-file-unix.c
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/osdep.h"
25 #include "qemu-common.h"
26 #include "qemu/error-report.h"
27 #include "qemu/iov.h"
28 #include "qemu/sockets.h"
29 #include "qemu/coroutine.h"
30 #include "migration/qemu-file.h"
31 #include "migration/qemu-file-internal.h"
32
33 typedef struct QEMUFileSocket {
34 int fd;
35 QEMUFile *file;
36 } QEMUFileSocket;
37
38 static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
39 int64_t pos)
40 {
41 QEMUFileSocket *s = opaque;
42 ssize_t len;
43 ssize_t size = iov_size(iov, iovcnt);
44 ssize_t offset = 0;
45 int err;
46
47 while (size > 0) {
48 len = iov_send(s->fd, iov, iovcnt, offset, size);
49
50 if (len > 0) {
51 size -= len;
52 offset += len;
53 }
54
55 if (size > 0) {
56 if (errno != EAGAIN && errno != EWOULDBLOCK) {
57 error_report("socket_writev_buffer: Got err=%d for (%zu/%zu)",
58 errno, (size_t)size, (size_t)len);
59 /*
60 * If I've already sent some but only just got the error, I
61 * could return the amount validly sent so far and wait for the
62 * next call to report the error, but I'd rather flag the error
63 * immediately.
64 */
65 return -errno;
66 }
67
68 /* Emulate blocking */
69 GPollFD pfd;
70
71 pfd.fd = s->fd;
72 pfd.events = G_IO_OUT | G_IO_ERR;
73 pfd.revents = 0;
74 TFR(err = g_poll(&pfd, 1, -1 /* no timeout */));
75 /* Errors other than EINTR intentionally ignored */
76 }
77 }
78
79 return offset;
80 }
81
82 static int socket_get_fd(void *opaque)
83 {
84 QEMUFileSocket *s = opaque;
85
86 return s->fd;
87 }
88
89 static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
90 size_t size)
91 {
92 QEMUFileSocket *s = opaque;
93 ssize_t len;
94
95 for (;;) {
96 len = qemu_recv(s->fd, buf, size, 0);
97 if (len != -1) {
98 break;
99 }
100 if (errno == EAGAIN) {
101 yield_until_fd_readable(s->fd);
102 } else if (errno != EINTR) {
103 break;
104 }
105 }
106
107 if (len == -1) {
108 len = -errno;
109 }
110 return len;
111 }
112
113 static int socket_close(void *opaque)
114 {
115 QEMUFileSocket *s = opaque;
116 closesocket(s->fd);
117 g_free(s);
118 return 0;
119 }
120
121 static int socket_shutdown(void *opaque, bool rd, bool wr)
122 {
123 QEMUFileSocket *s = opaque;
124
125 if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
126 return -errno;
127 } else {
128 return 0;
129 }
130 }
131
132 static int socket_return_close(void *opaque)
133 {
134 QEMUFileSocket *s = opaque;
135 /*
136 * Note: We don't close the socket, that should be done by the forward
137 * path.
138 */
139 g_free(s);
140 return 0;
141 }
142
143 static const QEMUFileOps socket_return_read_ops = {
144 .get_fd = socket_get_fd,
145 .get_buffer = socket_get_buffer,
146 .close = socket_return_close,
147 .shut_down = socket_shutdown,
148 };
149
150 static const QEMUFileOps socket_return_write_ops = {
151 .get_fd = socket_get_fd,
152 .writev_buffer = socket_writev_buffer,
153 .close = socket_return_close,
154 .shut_down = socket_shutdown,
155 };
156
157 /*
158 * Give a QEMUFile* off the same socket but data in the opposite
159 * direction.
160 */
161 static QEMUFile *socket_get_return_path(void *opaque)
162 {
163 QEMUFileSocket *forward = opaque;
164 QEMUFileSocket *reverse;
165
166 if (qemu_file_get_error(forward->file)) {
167 /* If the forward file is in error, don't try and open a return */
168 return NULL;
169 }
170
171 reverse = g_malloc0(sizeof(QEMUFileSocket));
172 reverse->fd = forward->fd;
173 /* I don't think there's a better way to tell which direction 'this' is */
174 if (forward->file->ops->get_buffer != NULL) {
175 /* being called from the read side, so we need to be able to write */
176 return qemu_fopen_ops(reverse, &socket_return_write_ops);
177 } else {
178 return qemu_fopen_ops(reverse, &socket_return_read_ops);
179 }
180 }
181
182 static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
183 int64_t pos)
184 {
185 QEMUFileSocket *s = opaque;
186 ssize_t len, offset;
187 ssize_t size = iov_size(iov, iovcnt);
188 ssize_t total = 0;
189
190 assert(iovcnt > 0);
191 offset = 0;
192 while (size > 0) {
193 /* Find the next start position; skip all full-sized vector elements */
194 while (offset >= iov[0].iov_len) {
195 offset -= iov[0].iov_len;
196 iov++, iovcnt--;
197 }
198
199 /* skip `offset' bytes from the (now) first element, undo it on exit */
200 assert(iovcnt > 0);
201 iov[0].iov_base += offset;
202 iov[0].iov_len -= offset;
203
204 do {
205 len = writev(s->fd, iov, iovcnt);
206 } while (len == -1 && errno == EINTR);
207 if (len == -1) {
208 return -errno;
209 }
210
211 /* Undo the changes above */
212 iov[0].iov_base -= offset;
213 iov[0].iov_len += offset;
214
215 /* Prepare for the next iteration */
216 offset += len;
217 total += len;
218 size -= len;
219 }
220
221 return total;
222 }
223
224 static ssize_t unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
225 size_t size)
226 {
227 QEMUFileSocket *s = opaque;
228 ssize_t len;
229
230 for (;;) {
231 len = read(s->fd, buf, size);
232 if (len != -1) {
233 break;
234 }
235 if (errno == EAGAIN) {
236 yield_until_fd_readable(s->fd);
237 } else if (errno != EINTR) {
238 break;
239 }
240 }
241
242 if (len == -1) {
243 len = -errno;
244 }
245 return len;
246 }
247
248 static int unix_close(void *opaque)
249 {
250 QEMUFileSocket *s = opaque;
251 close(s->fd);
252 g_free(s);
253 return 0;
254 }
255
256 static const QEMUFileOps unix_read_ops = {
257 .get_fd = socket_get_fd,
258 .get_buffer = unix_get_buffer,
259 .close = unix_close
260 };
261
262 static const QEMUFileOps unix_write_ops = {
263 .get_fd = socket_get_fd,
264 .writev_buffer = unix_writev_buffer,
265 .close = unix_close
266 };
267
268 QEMUFile *qemu_fdopen(int fd, const char *mode)
269 {
270 QEMUFileSocket *s;
271
272 if (mode == NULL ||
273 (mode[0] != 'r' && mode[0] != 'w') ||
274 mode[1] != 'b' || mode[2] != 0) {
275 fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
276 return NULL;
277 }
278
279 s = g_new0(QEMUFileSocket, 1);
280 s->fd = fd;
281
282 if (mode[0] == 'r') {
283 s->file = qemu_fopen_ops(s, &unix_read_ops);
284 } else {
285 s->file = qemu_fopen_ops(s, &unix_write_ops);
286 }
287 return s->file;
288 }
289
290 static const QEMUFileOps socket_read_ops = {
291 .get_fd = socket_get_fd,
292 .get_buffer = socket_get_buffer,
293 .close = socket_close,
294 .shut_down = socket_shutdown,
295 .get_return_path = socket_get_return_path
296 };
297
298 static const QEMUFileOps socket_write_ops = {
299 .get_fd = socket_get_fd,
300 .writev_buffer = socket_writev_buffer,
301 .close = socket_close,
302 .shut_down = socket_shutdown,
303 .get_return_path = socket_get_return_path
304 };
305
306 QEMUFile *qemu_fopen_socket(int fd, const char *mode)
307 {
308 QEMUFileSocket *s;
309
310 if (qemu_file_mode_is_not_valid(mode)) {
311 return NULL;
312 }
313
314 s = g_new0(QEMUFileSocket, 1);
315 s->fd = fd;
316 if (mode[0] == 'w') {
317 qemu_set_block(s->fd);
318 s->file = qemu_fopen_ops(s, &socket_write_ops);
319 } else {
320 s->file = qemu_fopen_ops(s, &socket_read_ops);
321 }
322 return s->file;
323 }