qemu/migration/qemu-file-channel.c
<<
>>
Prefs
   1/*
   2 * QEMUFile backend for QIOChannel objects
   3 *
   4 * Copyright (c) 2015-2016 Red Hat, Inc
   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
  25#include "qemu/osdep.h"
  26#include "migration/qemu-file.h"
  27#include "io/channel-socket.h"
  28#include "qemu/iov.h"
  29
  30
  31static ssize_t channel_writev_buffer(void *opaque,
  32                                     struct iovec *iov,
  33                                     int iovcnt,
  34                                     int64_t pos)
  35{
  36    QIOChannel *ioc = QIO_CHANNEL(opaque);
  37    ssize_t done = 0;
  38    struct iovec *local_iov = g_new(struct iovec, iovcnt);
  39    struct iovec *local_iov_head = local_iov;
  40    unsigned int nlocal_iov = iovcnt;
  41
  42    nlocal_iov = iov_copy(local_iov, nlocal_iov,
  43                          iov, iovcnt,
  44                          0, iov_size(iov, iovcnt));
  45
  46    while (nlocal_iov > 0) {
  47        ssize_t len;
  48        len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL);
  49        if (len == QIO_CHANNEL_ERR_BLOCK) {
  50            qio_channel_wait(ioc, G_IO_OUT);
  51            continue;
  52        }
  53        if (len < 0) {
  54            /* XXX handle Error objects */
  55            done = -EIO;
  56            goto cleanup;
  57        }
  58
  59        iov_discard_front(&local_iov, &nlocal_iov, len);
  60        done += len;
  61    }
  62
  63 cleanup:
  64    g_free(local_iov_head);
  65    return done;
  66}
  67
  68
  69static ssize_t channel_get_buffer(void *opaque,
  70                                  uint8_t *buf,
  71                                  int64_t pos,
  72                                  size_t size)
  73{
  74    QIOChannel *ioc = QIO_CHANNEL(opaque);
  75    ssize_t ret;
  76
  77    do {
  78        ret = qio_channel_read(ioc, (char *)buf, size, NULL);
  79        if (ret < 0) {
  80            if (ret == QIO_CHANNEL_ERR_BLOCK) {
  81                qio_channel_yield(ioc, G_IO_IN);
  82            } else {
  83                /* XXX handle Error * object */
  84                return -EIO;
  85            }
  86        }
  87    } while (ret == QIO_CHANNEL_ERR_BLOCK);
  88
  89    return ret;
  90}
  91
  92
  93static int channel_close(void *opaque)
  94{
  95    QIOChannel *ioc = QIO_CHANNEL(opaque);
  96    qio_channel_close(ioc, NULL);
  97    object_unref(OBJECT(ioc));
  98    return 0;
  99}
 100
 101
 102static int channel_shutdown(void *opaque,
 103                            bool rd,
 104                            bool wr)
 105{
 106    QIOChannel *ioc = QIO_CHANNEL(opaque);
 107
 108    if (qio_channel_has_feature(ioc,
 109                                QIO_CHANNEL_FEATURE_SHUTDOWN)) {
 110        QIOChannelShutdown mode;
 111        if (rd && wr) {
 112            mode = QIO_CHANNEL_SHUTDOWN_BOTH;
 113        } else if (rd) {
 114            mode = QIO_CHANNEL_SHUTDOWN_READ;
 115        } else {
 116            mode = QIO_CHANNEL_SHUTDOWN_WRITE;
 117        }
 118        if (qio_channel_shutdown(ioc, mode, NULL) < 0) {
 119            /* XXX handler Error * object */
 120            return -EIO;
 121        }
 122    }
 123    return 0;
 124}
 125
 126
 127static int channel_set_blocking(void *opaque,
 128                                bool enabled)
 129{
 130    QIOChannel *ioc = QIO_CHANNEL(opaque);
 131
 132    if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) {
 133        return -1;
 134    }
 135    return 0;
 136}
 137
 138static QEMUFile *channel_get_input_return_path(void *opaque)
 139{
 140    QIOChannel *ioc = QIO_CHANNEL(opaque);
 141
 142    return qemu_fopen_channel_output(ioc);
 143}
 144
 145static QEMUFile *channel_get_output_return_path(void *opaque)
 146{
 147    QIOChannel *ioc = QIO_CHANNEL(opaque);
 148
 149    return qemu_fopen_channel_input(ioc);
 150}
 151
 152static const QEMUFileOps channel_input_ops = {
 153    .get_buffer = channel_get_buffer,
 154    .close = channel_close,
 155    .shut_down = channel_shutdown,
 156    .set_blocking = channel_set_blocking,
 157    .get_return_path = channel_get_input_return_path,
 158};
 159
 160
 161static const QEMUFileOps channel_output_ops = {
 162    .writev_buffer = channel_writev_buffer,
 163    .close = channel_close,
 164    .shut_down = channel_shutdown,
 165    .set_blocking = channel_set_blocking,
 166    .get_return_path = channel_get_output_return_path,
 167};
 168
 169
 170QEMUFile *qemu_fopen_channel_input(QIOChannel *ioc)
 171{
 172    object_ref(OBJECT(ioc));
 173    return qemu_fopen_ops(ioc, &channel_input_ops);
 174}
 175
 176QEMUFile *qemu_fopen_channel_output(QIOChannel *ioc)
 177{
 178    object_ref(OBJECT(ioc));
 179    return qemu_fopen_ops(ioc, &channel_output_ops);
 180}
 181