Add qemu 2.4.0
[kvmfornfv.git] / qemu / 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-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
31 typedef struct QEMUFileSocket {
32     int fd;
33     QEMUFile *file;
34 } QEMUFileSocket;
35
36 static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
37                                     int64_t pos)
38 {
39     QEMUFileSocket *s = opaque;
40     ssize_t len;
41     ssize_t size = iov_size(iov, iovcnt);
42
43     len = iov_send(s->fd, iov, iovcnt, 0, size);
44     if (len < size) {
45         len = -socket_error();
46     }
47     return len;
48 }
49
50 static int socket_get_fd(void *opaque)
51 {
52     QEMUFileSocket *s = opaque;
53
54     return s->fd;
55 }
56
57 static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
58 {
59     QEMUFileSocket *s = opaque;
60     ssize_t len;
61
62     for (;;) {
63         len = qemu_recv(s->fd, buf, size, 0);
64         if (len != -1) {
65             break;
66         }
67         if (socket_error() == EAGAIN) {
68             yield_until_fd_readable(s->fd);
69         } else if (socket_error() != EINTR) {
70             break;
71         }
72     }
73
74     if (len == -1) {
75         len = -socket_error();
76     }
77     return len;
78 }
79
80 static int socket_close(void *opaque)
81 {
82     QEMUFileSocket *s = opaque;
83     closesocket(s->fd);
84     g_free(s);
85     return 0;
86 }
87
88 static int socket_shutdown(void *opaque, bool rd, bool wr)
89 {
90     QEMUFileSocket *s = opaque;
91
92     if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
93         return -errno;
94     } else {
95         return 0;
96     }
97 }
98
99 static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
100                                   int64_t pos)
101 {
102     QEMUFileSocket *s = opaque;
103     ssize_t len, offset;
104     ssize_t size = iov_size(iov, iovcnt);
105     ssize_t total = 0;
106
107     assert(iovcnt > 0);
108     offset = 0;
109     while (size > 0) {
110         /* Find the next start position; skip all full-sized vector elements  */
111         while (offset >= iov[0].iov_len) {
112             offset -= iov[0].iov_len;
113             iov++, iovcnt--;
114         }
115
116         /* skip `offset' bytes from the (now) first element, undo it on exit */
117         assert(iovcnt > 0);
118         iov[0].iov_base += offset;
119         iov[0].iov_len -= offset;
120
121         do {
122             len = writev(s->fd, iov, iovcnt);
123         } while (len == -1 && errno == EINTR);
124         if (len == -1) {
125             return -errno;
126         }
127
128         /* Undo the changes above */
129         iov[0].iov_base -= offset;
130         iov[0].iov_len += offset;
131
132         /* Prepare for the next iteration */
133         offset += len;
134         total += len;
135         size -= len;
136     }
137
138     return total;
139 }
140
141 static int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
142 {
143     QEMUFileSocket *s = opaque;
144     ssize_t len;
145
146     for (;;) {
147         len = read(s->fd, buf, size);
148         if (len != -1) {
149             break;
150         }
151         if (errno == EAGAIN) {
152             yield_until_fd_readable(s->fd);
153         } else if (errno != EINTR) {
154             break;
155         }
156     }
157
158     if (len == -1) {
159         len = -errno;
160     }
161     return len;
162 }
163
164 static int unix_close(void *opaque)
165 {
166     QEMUFileSocket *s = opaque;
167     close(s->fd);
168     g_free(s);
169     return 0;
170 }
171
172 static const QEMUFileOps unix_read_ops = {
173     .get_fd =     socket_get_fd,
174     .get_buffer = unix_get_buffer,
175     .close =      unix_close
176 };
177
178 static const QEMUFileOps unix_write_ops = {
179     .get_fd =     socket_get_fd,
180     .writev_buffer = unix_writev_buffer,
181     .close =      unix_close
182 };
183
184 QEMUFile *qemu_fdopen(int fd, const char *mode)
185 {
186     QEMUFileSocket *s;
187
188     if (mode == NULL ||
189         (mode[0] != 'r' && mode[0] != 'w') ||
190         mode[1] != 'b' || mode[2] != 0) {
191         fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
192         return NULL;
193     }
194
195     s = g_malloc0(sizeof(QEMUFileSocket));
196     s->fd = fd;
197
198     if (mode[0] == 'r') {
199         s->file = qemu_fopen_ops(s, &unix_read_ops);
200     } else {
201         s->file = qemu_fopen_ops(s, &unix_write_ops);
202     }
203     return s->file;
204 }
205
206 static const QEMUFileOps socket_read_ops = {
207     .get_fd     = socket_get_fd,
208     .get_buffer = socket_get_buffer,
209     .close      = socket_close,
210     .shut_down  = socket_shutdown
211
212 };
213
214 static const QEMUFileOps socket_write_ops = {
215     .get_fd        = socket_get_fd,
216     .writev_buffer = socket_writev_buffer,
217     .close         = socket_close,
218     .shut_down     = socket_shutdown
219 };
220
221 QEMUFile *qemu_fopen_socket(int fd, const char *mode)
222 {
223     QEMUFileSocket *s;
224
225     if (qemu_file_mode_is_not_valid(mode)) {
226         return NULL;
227     }
228
229     s = g_malloc0(sizeof(QEMUFileSocket));
230     s->fd = fd;
231     if (mode[0] == 'w') {
232         qemu_set_block(s->fd);
233         s->file = qemu_fopen_ops(s, &socket_write_ops);
234     } else {
235         s->file = qemu_fopen_ops(s, &socket_read_ops);
236     }
237     return s->file;
238 }