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