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