qemu/migration/qemu-file-unix.c
<<
>>
Prefs
   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
  33typedef struct QEMUFileSocket {
  34    int fd;
  35    QEMUFile *file;
  36} QEMUFileSocket;
  37
  38static 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
  82static int socket_get_fd(void *opaque)
  83{
  84    QEMUFileSocket *s = opaque;
  85
  86    return s->fd;
  87}
  88
  89static 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
 113static int socket_close(void *opaque)
 114{
 115    QEMUFileSocket *s = opaque;
 116    closesocket(s->fd);
 117    g_free(s);
 118    return 0;
 119}
 120
 121static 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
 132static 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
 143static 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
 150static 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 */
 161static 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
 182static 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
 224static 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
 248static int unix_close(void *opaque)
 249{
 250    QEMUFileSocket *s = opaque;
 251    close(s->fd);
 252    g_free(s);
 253    return 0;
 254}
 255
 256static const QEMUFileOps unix_read_ops = {
 257    .get_fd =     socket_get_fd,
 258    .get_buffer = unix_get_buffer,
 259    .close =      unix_close
 260};
 261
 262static const QEMUFileOps unix_write_ops = {
 263    .get_fd =     socket_get_fd,
 264    .writev_buffer = unix_writev_buffer,
 265    .close =      unix_close
 266};
 267
 268QEMUFile *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
 290static 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
 298static 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
 306QEMUFile *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}
 324