xref: /openbmc/qemu/io/channel-buffer.c (revision b86307ecef9222c335ebd0ed4da2b243e86f779e)
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