1d98e4eb7SDaniel P. Berrange /*
2d98e4eb7SDaniel P. Berrange * QEMU I/O channels memory buffer driver
3d98e4eb7SDaniel P. Berrange *
4d98e4eb7SDaniel P. Berrange * Copyright (c) 2015 Red Hat, Inc.
5d98e4eb7SDaniel P. Berrange *
6d98e4eb7SDaniel P. Berrange * This library is free software; you can redistribute it and/or
7d98e4eb7SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public
8d98e4eb7SDaniel P. Berrange * License as published by the Free Software Foundation; either
9c8198bd5SChetan Pant * version 2.1 of the License, or (at your option) any later version.
10d98e4eb7SDaniel P. Berrange *
11d98e4eb7SDaniel P. Berrange * This library is distributed in the hope that it will be useful,
12d98e4eb7SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
13d98e4eb7SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14d98e4eb7SDaniel P. Berrange * Lesser General Public License for more details.
15d98e4eb7SDaniel P. Berrange *
16d98e4eb7SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public
17d98e4eb7SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18d98e4eb7SDaniel P. Berrange *
19d98e4eb7SDaniel P. Berrange */
20d98e4eb7SDaniel P. Berrange
21cae9fc56SPeter Maydell #include "qemu/osdep.h"
22d98e4eb7SDaniel P. Berrange #include "io/channel-buffer.h"
23d98e4eb7SDaniel P. Berrange #include "io/channel-watch.h"
240b8fa32fSMarkus Armbruster #include "qemu/module.h"
25d98e4eb7SDaniel P. Berrange #include "qemu/sockets.h"
26d98e4eb7SDaniel P. Berrange #include "trace.h"
27d98e4eb7SDaniel P. Berrange
28d98e4eb7SDaniel P. Berrange QIOChannelBuffer *
qio_channel_buffer_new(size_t capacity)29d98e4eb7SDaniel P. Berrange qio_channel_buffer_new(size_t capacity)
30d98e4eb7SDaniel P. Berrange {
31d98e4eb7SDaniel P. Berrange QIOChannelBuffer *ioc;
32d98e4eb7SDaniel P. Berrange
33d98e4eb7SDaniel P. Berrange ioc = QIO_CHANNEL_BUFFER(object_new(TYPE_QIO_CHANNEL_BUFFER));
34d98e4eb7SDaniel P. Berrange
35d98e4eb7SDaniel P. Berrange if (capacity) {
36e8f117f3SDaniel P. Berrange ioc->data = g_new0(uint8_t, capacity);
37d98e4eb7SDaniel P. Berrange ioc->capacity = capacity;
38d98e4eb7SDaniel P. Berrange }
39d98e4eb7SDaniel P. Berrange
40d98e4eb7SDaniel P. Berrange return ioc;
41d98e4eb7SDaniel P. Berrange }
42d98e4eb7SDaniel P. Berrange
43d98e4eb7SDaniel P. Berrange
qio_channel_buffer_finalize(Object * obj)44d98e4eb7SDaniel P. Berrange static void qio_channel_buffer_finalize(Object *obj)
45d98e4eb7SDaniel P. Berrange {
46d98e4eb7SDaniel P. Berrange QIOChannelBuffer *ioc = QIO_CHANNEL_BUFFER(obj);
47d98e4eb7SDaniel P. Berrange g_free(ioc->data);
48d98e4eb7SDaniel P. Berrange ioc->capacity = ioc->usage = ioc->offset = 0;
49d98e4eb7SDaniel P. Berrange }
50d98e4eb7SDaniel P. Berrange
51d98e4eb7SDaniel P. Berrange
qio_channel_buffer_readv(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,int flags,Error ** errp)52d98e4eb7SDaniel P. Berrange static ssize_t qio_channel_buffer_readv(QIOChannel *ioc,
53d98e4eb7SDaniel P. Berrange const struct iovec *iov,
54d98e4eb7SDaniel P. Berrange size_t niov,
55d98e4eb7SDaniel P. Berrange int **fds,
56d98e4eb7SDaniel P. Berrange size_t *nfds,
57*84615a19Smanish.mishra int flags,
58d98e4eb7SDaniel P. Berrange Error **errp)
59d98e4eb7SDaniel P. Berrange {
60d98e4eb7SDaniel P. Berrange QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
61d98e4eb7SDaniel P. Berrange ssize_t ret = 0;
62d98e4eb7SDaniel P. Berrange size_t i;
63d98e4eb7SDaniel P. Berrange
64d98e4eb7SDaniel P. Berrange for (i = 0; i < niov; i++) {
65d98e4eb7SDaniel P. Berrange size_t want = iov[i].iov_len;
66d98e4eb7SDaniel P. Berrange if (bioc->offset >= bioc->usage) {
67d98e4eb7SDaniel P. Berrange break;
68d98e4eb7SDaniel P. Berrange }
69d98e4eb7SDaniel P. Berrange if ((bioc->offset + want) > bioc->usage) {
70d98e4eb7SDaniel P. Berrange want = bioc->usage - bioc->offset;
71d98e4eb7SDaniel P. Berrange }
72d98e4eb7SDaniel P. Berrange memcpy(iov[i].iov_base, bioc->data + bioc->offset, want);
73d98e4eb7SDaniel P. Berrange ret += want;
74d98e4eb7SDaniel P. Berrange bioc->offset += want;
75d98e4eb7SDaniel P. Berrange }
76d98e4eb7SDaniel P. Berrange
77d98e4eb7SDaniel P. Berrange return ret;
78d98e4eb7SDaniel P. Berrange }
79d98e4eb7SDaniel P. Berrange
qio_channel_buffer_writev(QIOChannel * ioc,const struct iovec * iov,size_t niov,int * fds,size_t nfds,int flags,Error ** errp)80d98e4eb7SDaniel P. Berrange static ssize_t qio_channel_buffer_writev(QIOChannel *ioc,
81d98e4eb7SDaniel P. Berrange const struct iovec *iov,
82d98e4eb7SDaniel P. Berrange size_t niov,
83d98e4eb7SDaniel P. Berrange int *fds,
84d98e4eb7SDaniel P. Berrange size_t nfds,
85b88651cbSLeonardo Bras int flags,
86d98e4eb7SDaniel P. Berrange Error **errp)
87d98e4eb7SDaniel P. Berrange {
88d98e4eb7SDaniel P. Berrange QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
89d98e4eb7SDaniel P. Berrange ssize_t ret = 0;
90d98e4eb7SDaniel P. Berrange size_t i;
91d98e4eb7SDaniel P. Berrange size_t towrite = 0;
92d98e4eb7SDaniel P. Berrange
93d98e4eb7SDaniel P. Berrange for (i = 0; i < niov; i++) {
94d98e4eb7SDaniel P. Berrange towrite += iov[i].iov_len;
95d98e4eb7SDaniel P. Berrange }
96d98e4eb7SDaniel P. Berrange
97d98e4eb7SDaniel P. Berrange if ((bioc->offset + towrite) > bioc->capacity) {
98d98e4eb7SDaniel P. Berrange bioc->capacity = bioc->offset + towrite;
99d98e4eb7SDaniel P. Berrange bioc->data = g_realloc(bioc->data, bioc->capacity);
100d98e4eb7SDaniel P. Berrange }
101d98e4eb7SDaniel P. Berrange
102d98e4eb7SDaniel P. Berrange if (bioc->offset > bioc->usage) {
103d98e4eb7SDaniel P. Berrange memset(bioc->data, 0, bioc->offset - bioc->usage);
104d98e4eb7SDaniel P. Berrange bioc->usage = bioc->offset;
105d98e4eb7SDaniel P. Berrange }
106d98e4eb7SDaniel P. Berrange
107d98e4eb7SDaniel P. Berrange for (i = 0; i < niov; i++) {
108d98e4eb7SDaniel P. Berrange memcpy(bioc->data + bioc->usage,
109d98e4eb7SDaniel P. Berrange iov[i].iov_base,
110d98e4eb7SDaniel P. Berrange iov[i].iov_len);
111d98e4eb7SDaniel P. Berrange bioc->usage += iov[i].iov_len;
112d98e4eb7SDaniel P. Berrange bioc->offset += iov[i].iov_len;
113d98e4eb7SDaniel P. Berrange ret += iov[i].iov_len;
114d98e4eb7SDaniel P. Berrange }
115d98e4eb7SDaniel P. Berrange
116d98e4eb7SDaniel P. Berrange return ret;
117d98e4eb7SDaniel P. Berrange }
118d98e4eb7SDaniel P. Berrange
qio_channel_buffer_set_blocking(QIOChannel * ioc G_GNUC_UNUSED,bool enabled G_GNUC_UNUSED,Error ** errp G_GNUC_UNUSED)119d98e4eb7SDaniel P. Berrange static int qio_channel_buffer_set_blocking(QIOChannel *ioc G_GNUC_UNUSED,
120d98e4eb7SDaniel P. Berrange bool enabled G_GNUC_UNUSED,
121d98e4eb7SDaniel P. Berrange Error **errp G_GNUC_UNUSED)
122d98e4eb7SDaniel P. Berrange {
123d98e4eb7SDaniel P. Berrange return 0;
124d98e4eb7SDaniel P. Berrange }
125d98e4eb7SDaniel P. Berrange
126d98e4eb7SDaniel P. Berrange
qio_channel_buffer_seek(QIOChannel * ioc,off_t offset,int whence,Error ** errp)127d98e4eb7SDaniel P. Berrange static off_t qio_channel_buffer_seek(QIOChannel *ioc,
128d98e4eb7SDaniel P. Berrange off_t offset,
129d98e4eb7SDaniel P. Berrange int whence,
130d98e4eb7SDaniel P. Berrange Error **errp)
131d98e4eb7SDaniel P. Berrange {
132d98e4eb7SDaniel P. Berrange QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
133d98e4eb7SDaniel P. Berrange
134d98e4eb7SDaniel P. Berrange bioc->offset = offset;
135d98e4eb7SDaniel P. Berrange
136d98e4eb7SDaniel P. Berrange return offset;
137d98e4eb7SDaniel P. Berrange }
138d98e4eb7SDaniel P. Berrange
139d98e4eb7SDaniel P. Berrange
qio_channel_buffer_close(QIOChannel * ioc,Error ** errp)140d98e4eb7SDaniel P. Berrange static int qio_channel_buffer_close(QIOChannel *ioc,
141d98e4eb7SDaniel P. Berrange Error **errp)
142d98e4eb7SDaniel P. Berrange {
143d98e4eb7SDaniel P. Berrange QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
144d98e4eb7SDaniel P. Berrange
145d98e4eb7SDaniel P. Berrange g_free(bioc->data);
146d656ec5eSDaniel P. Berrange bioc->data = NULL;
147d98e4eb7SDaniel P. Berrange bioc->capacity = bioc->usage = bioc->offset = 0;
148d98e4eb7SDaniel P. Berrange
149d98e4eb7SDaniel P. Berrange return 0;
150d98e4eb7SDaniel P. Berrange }
151d98e4eb7SDaniel P. Berrange
152d98e4eb7SDaniel P. Berrange
153d98e4eb7SDaniel P. Berrange typedef struct QIOChannelBufferSource QIOChannelBufferSource;
154d98e4eb7SDaniel P. Berrange struct QIOChannelBufferSource {
155d98e4eb7SDaniel P. Berrange GSource parent;
156d98e4eb7SDaniel P. Berrange QIOChannelBuffer *bioc;
157d98e4eb7SDaniel P. Berrange GIOCondition condition;
158d98e4eb7SDaniel P. Berrange };
159d98e4eb7SDaniel P. Berrange
160d98e4eb7SDaniel P. Berrange static gboolean
qio_channel_buffer_source_prepare(GSource * source,gint * timeout)161d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_prepare(GSource *source,
162d98e4eb7SDaniel P. Berrange gint *timeout)
163d98e4eb7SDaniel P. Berrange {
164d98e4eb7SDaniel P. Berrange QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
165d98e4eb7SDaniel P. Berrange
166d98e4eb7SDaniel P. Berrange *timeout = -1;
167d98e4eb7SDaniel P. Berrange
168d98e4eb7SDaniel P. Berrange return (G_IO_IN | G_IO_OUT) & bsource->condition;
169d98e4eb7SDaniel P. Berrange }
170d98e4eb7SDaniel P. Berrange
171d98e4eb7SDaniel P. Berrange static gboolean
qio_channel_buffer_source_check(GSource * source)172d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_check(GSource *source)
173d98e4eb7SDaniel P. Berrange {
174d98e4eb7SDaniel P. Berrange QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
175d98e4eb7SDaniel P. Berrange
176d98e4eb7SDaniel P. Berrange return (G_IO_IN | G_IO_OUT) & bsource->condition;
177d98e4eb7SDaniel P. Berrange }
178d98e4eb7SDaniel P. Berrange
179d98e4eb7SDaniel P. Berrange static gboolean
qio_channel_buffer_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)180d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_dispatch(GSource *source,
181d98e4eb7SDaniel P. Berrange GSourceFunc callback,
182d98e4eb7SDaniel P. Berrange gpointer user_data)
183d98e4eb7SDaniel P. Berrange {
184d98e4eb7SDaniel P. Berrange QIOChannelFunc func = (QIOChannelFunc)callback;
185d98e4eb7SDaniel P. Berrange QIOChannelBufferSource *bsource = (QIOChannelBufferSource *)source;
186d98e4eb7SDaniel P. Berrange
187d98e4eb7SDaniel P. Berrange return (*func)(QIO_CHANNEL(bsource->bioc),
188d98e4eb7SDaniel P. Berrange ((G_IO_IN | G_IO_OUT) & bsource->condition),
189d98e4eb7SDaniel P. Berrange user_data);
190d98e4eb7SDaniel P. Berrange }
191d98e4eb7SDaniel P. Berrange
192d98e4eb7SDaniel P. Berrange static void
qio_channel_buffer_source_finalize(GSource * source)193d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_finalize(GSource *source)
194d98e4eb7SDaniel P. Berrange {
195d98e4eb7SDaniel P. Berrange QIOChannelBufferSource *ssource = (QIOChannelBufferSource *)source;
196d98e4eb7SDaniel P. Berrange
197d98e4eb7SDaniel P. Berrange object_unref(OBJECT(ssource->bioc));
198d98e4eb7SDaniel P. Berrange }
199d98e4eb7SDaniel P. Berrange
200d98e4eb7SDaniel P. Berrange GSourceFuncs qio_channel_buffer_source_funcs = {
201d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_prepare,
202d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_check,
203d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_dispatch,
204d98e4eb7SDaniel P. Berrange qio_channel_buffer_source_finalize
205d98e4eb7SDaniel P. Berrange };
206d98e4eb7SDaniel P. Berrange
qio_channel_buffer_create_watch(QIOChannel * ioc,GIOCondition condition)207d98e4eb7SDaniel P. Berrange static GSource *qio_channel_buffer_create_watch(QIOChannel *ioc,
208d98e4eb7SDaniel P. Berrange GIOCondition condition)
209d98e4eb7SDaniel P. Berrange {
210d98e4eb7SDaniel P. Berrange QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
211d98e4eb7SDaniel P. Berrange QIOChannelBufferSource *ssource;
212d98e4eb7SDaniel P. Berrange GSource *source;
213d98e4eb7SDaniel P. Berrange
214d98e4eb7SDaniel P. Berrange source = g_source_new(&qio_channel_buffer_source_funcs,
215d98e4eb7SDaniel P. Berrange sizeof(QIOChannelBufferSource));
216d98e4eb7SDaniel P. Berrange ssource = (QIOChannelBufferSource *)source;
217d98e4eb7SDaniel P. Berrange
218d98e4eb7SDaniel P. Berrange ssource->bioc = bioc;
219d98e4eb7SDaniel P. Berrange object_ref(OBJECT(bioc));
220d98e4eb7SDaniel P. Berrange
221d98e4eb7SDaniel P. Berrange ssource->condition = condition;
222d98e4eb7SDaniel P. Berrange
223d98e4eb7SDaniel P. Berrange return source;
224d98e4eb7SDaniel P. Berrange }
225d98e4eb7SDaniel P. Berrange
226d98e4eb7SDaniel P. Berrange
qio_channel_buffer_class_init(ObjectClass * klass,void * class_data G_GNUC_UNUSED)227d98e4eb7SDaniel P. Berrange static void qio_channel_buffer_class_init(ObjectClass *klass,
228d98e4eb7SDaniel P. Berrange void *class_data G_GNUC_UNUSED)
229d98e4eb7SDaniel P. Berrange {
230d98e4eb7SDaniel P. Berrange QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
231d98e4eb7SDaniel P. Berrange
232d98e4eb7SDaniel P. Berrange ioc_klass->io_writev = qio_channel_buffer_writev;
233d98e4eb7SDaniel P. Berrange ioc_klass->io_readv = qio_channel_buffer_readv;
234d98e4eb7SDaniel P. Berrange ioc_klass->io_set_blocking = qio_channel_buffer_set_blocking;
235d98e4eb7SDaniel P. Berrange ioc_klass->io_seek = qio_channel_buffer_seek;
236d98e4eb7SDaniel P. Berrange ioc_klass->io_close = qio_channel_buffer_close;
237d98e4eb7SDaniel P. Berrange ioc_klass->io_create_watch = qio_channel_buffer_create_watch;
238d98e4eb7SDaniel P. Berrange }
239d98e4eb7SDaniel P. Berrange
240d98e4eb7SDaniel P. Berrange static const TypeInfo qio_channel_buffer_info = {
241d98e4eb7SDaniel P. Berrange .parent = TYPE_QIO_CHANNEL,
242d98e4eb7SDaniel P. Berrange .name = TYPE_QIO_CHANNEL_BUFFER,
243d98e4eb7SDaniel P. Berrange .instance_size = sizeof(QIOChannelBuffer),
244d98e4eb7SDaniel P. Berrange .instance_finalize = qio_channel_buffer_finalize,
245d98e4eb7SDaniel P. Berrange .class_init = qio_channel_buffer_class_init,
246d98e4eb7SDaniel P. Berrange };
247d98e4eb7SDaniel P. Berrange
qio_channel_buffer_register_types(void)248d98e4eb7SDaniel P. Berrange static void qio_channel_buffer_register_types(void)
249d98e4eb7SDaniel P. Berrange {
250d98e4eb7SDaniel P. Berrange type_register_static(&qio_channel_buffer_info);
251d98e4eb7SDaniel P. Berrange }
252d98e4eb7SDaniel P. Berrange
253d98e4eb7SDaniel P. Berrange type_init(qio_channel_buffer_register_types);
254