1894593afSMarc-André Lureau /*
2894593afSMarc-André Lureau * QEMU System Emulator
3894593afSMarc-André Lureau *
4894593afSMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard
5894593afSMarc-André Lureau *
6894593afSMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy
7894593afSMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal
8894593afSMarc-André Lureau * in the Software without restriction, including without limitation the rights
9894593afSMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10894593afSMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is
11894593afSMarc-André Lureau * furnished to do so, subject to the following conditions:
12894593afSMarc-André Lureau *
13894593afSMarc-André Lureau * The above copyright notice and this permission notice shall be included in
14894593afSMarc-André Lureau * all copies or substantial portions of the Software.
15894593afSMarc-André Lureau *
16894593afSMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17894593afSMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18894593afSMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19894593afSMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20894593afSMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21894593afSMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22894593afSMarc-André Lureau * THE SOFTWARE.
23894593afSMarc-André Lureau */
240b8fa32fSMarkus Armbruster
25894593afSMarc-André Lureau #include "qemu/osdep.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
27894593afSMarc-André Lureau #include "qemu/sockets.h"
28894593afSMarc-André Lureau #include "qapi/error.h"
298228e353SMarc-André Lureau #include "chardev/char.h"
30bb2b058fSMarc-André Lureau #include "chardev/char-fe.h"
31894593afSMarc-André Lureau #include "io/channel-file.h"
32894593afSMarc-André Lureau
338228e353SMarc-André Lureau #include "chardev/char-fd.h"
348228e353SMarc-André Lureau #include "chardev/char-io.h"
35894593afSMarc-André Lureau
36894593afSMarc-André Lureau /* Called with chr_write_lock held. */
fd_chr_write(Chardev * chr,const uint8_t * buf,int len)37894593afSMarc-André Lureau static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
38894593afSMarc-André Lureau {
39894593afSMarc-André Lureau FDChardev *s = FD_CHARDEV(chr);
40894593afSMarc-André Lureau
4146fe3ff6SMarc-André Lureau if (!s->ioc_out) {
4246fe3ff6SMarc-André Lureau return -1;
4346fe3ff6SMarc-André Lureau }
4446fe3ff6SMarc-André Lureau
45894593afSMarc-André Lureau return io_channel_send(s->ioc_out, buf, len);
46894593afSMarc-André Lureau }
47894593afSMarc-André Lureau
fd_chr_read(QIOChannel * chan,GIOCondition cond,void * opaque)48894593afSMarc-André Lureau static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
49894593afSMarc-André Lureau {
50894593afSMarc-André Lureau Chardev *chr = CHARDEV(opaque);
51894593afSMarc-André Lureau FDChardev *s = FD_CHARDEV(opaque);
52894593afSMarc-André Lureau int len;
53894593afSMarc-André Lureau uint8_t buf[CHR_READ_BUF_LEN];
54894593afSMarc-André Lureau ssize_t ret;
55894593afSMarc-André Lureau
56894593afSMarc-André Lureau len = sizeof(buf);
57894593afSMarc-André Lureau if (len > s->max_size) {
58894593afSMarc-André Lureau len = s->max_size;
59894593afSMarc-André Lureau }
60894593afSMarc-André Lureau if (len == 0) {
61894593afSMarc-André Lureau return TRUE;
62894593afSMarc-André Lureau }
63894593afSMarc-André Lureau
64894593afSMarc-André Lureau ret = qio_channel_read(
65894593afSMarc-André Lureau chan, (gchar *)buf, len, NULL);
66894593afSMarc-André Lureau if (ret == 0) {
67b19456ddSzhanghailiang remove_fd_in_watch(chr);
68894593afSMarc-André Lureau qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
69894593afSMarc-André Lureau return FALSE;
70894593afSMarc-André Lureau }
71894593afSMarc-André Lureau if (ret > 0) {
72894593afSMarc-André Lureau qemu_chr_be_write(chr, buf, ret);
73894593afSMarc-André Lureau }
74894593afSMarc-André Lureau
75894593afSMarc-André Lureau return TRUE;
76894593afSMarc-André Lureau }
77894593afSMarc-André Lureau
fd_chr_read_poll(void * opaque)78894593afSMarc-André Lureau static int fd_chr_read_poll(void *opaque)
79894593afSMarc-André Lureau {
80894593afSMarc-André Lureau Chardev *chr = CHARDEV(opaque);
81894593afSMarc-André Lureau FDChardev *s = FD_CHARDEV(opaque);
82894593afSMarc-André Lureau
83894593afSMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr);
84894593afSMarc-André Lureau return s->max_size;
85894593afSMarc-André Lureau }
86894593afSMarc-André Lureau
87bb2b058fSMarc-André Lureau typedef struct FDSource {
88bb2b058fSMarc-André Lureau GSource parent;
89bb2b058fSMarc-André Lureau
90bb2b058fSMarc-André Lureau GIOCondition cond;
91bb2b058fSMarc-André Lureau } FDSource;
92bb2b058fSMarc-André Lureau
93bb2b058fSMarc-André Lureau static gboolean
fd_source_prepare(GSource * source,gint * timeout_)94bb2b058fSMarc-André Lureau fd_source_prepare(GSource *source,
95bb2b058fSMarc-André Lureau gint *timeout_)
96bb2b058fSMarc-André Lureau {
97bb2b058fSMarc-André Lureau FDSource *src = (FDSource *)source;
98bb2b058fSMarc-André Lureau
99bb2b058fSMarc-André Lureau return src->cond != 0;
100bb2b058fSMarc-André Lureau }
101bb2b058fSMarc-André Lureau
102bb2b058fSMarc-André Lureau static gboolean
fd_source_check(GSource * source)103bb2b058fSMarc-André Lureau fd_source_check(GSource *source)
104bb2b058fSMarc-André Lureau {
105bb2b058fSMarc-André Lureau FDSource *src = (FDSource *)source;
106bb2b058fSMarc-André Lureau
107bb2b058fSMarc-André Lureau return src->cond != 0;
108bb2b058fSMarc-André Lureau }
109bb2b058fSMarc-André Lureau
110bb2b058fSMarc-André Lureau static gboolean
fd_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)111bb2b058fSMarc-André Lureau fd_source_dispatch(GSource *source, GSourceFunc callback,
112bb2b058fSMarc-André Lureau gpointer user_data)
113bb2b058fSMarc-André Lureau {
114bb2b058fSMarc-André Lureau FDSource *src = (FDSource *)source;
115bb2b058fSMarc-André Lureau FEWatchFunc func = (FEWatchFunc)callback;
116bb2b058fSMarc-André Lureau gboolean ret = G_SOURCE_CONTINUE;
117bb2b058fSMarc-André Lureau
118bb2b058fSMarc-André Lureau if (src->cond) {
119bb2b058fSMarc-André Lureau ret = func(NULL, src->cond, user_data);
120bb2b058fSMarc-André Lureau src->cond = 0;
121bb2b058fSMarc-André Lureau }
122bb2b058fSMarc-André Lureau
123bb2b058fSMarc-André Lureau return ret;
124bb2b058fSMarc-André Lureau }
125bb2b058fSMarc-André Lureau
126bb2b058fSMarc-André Lureau static GSourceFuncs fd_source_funcs = {
127bb2b058fSMarc-André Lureau fd_source_prepare,
128bb2b058fSMarc-André Lureau fd_source_check,
129bb2b058fSMarc-André Lureau fd_source_dispatch,
130bb2b058fSMarc-André Lureau NULL, NULL, NULL
131bb2b058fSMarc-André Lureau };
132bb2b058fSMarc-André Lureau
fd_source_new(FDChardev * chr)133bb2b058fSMarc-André Lureau static GSource *fd_source_new(FDChardev *chr)
134bb2b058fSMarc-André Lureau {
135bb2b058fSMarc-André Lureau return g_source_new(&fd_source_funcs, sizeof(FDSource));
136bb2b058fSMarc-André Lureau }
137bb2b058fSMarc-André Lureau
child_func(GIOChannel * source,GIOCondition condition,gpointer data)138bb2b058fSMarc-André Lureau static gboolean child_func(GIOChannel *source,
139bb2b058fSMarc-André Lureau GIOCondition condition,
140bb2b058fSMarc-André Lureau gpointer data)
141bb2b058fSMarc-André Lureau {
142bb2b058fSMarc-André Lureau FDSource *parent = data;
143bb2b058fSMarc-André Lureau
144bb2b058fSMarc-André Lureau parent->cond |= condition;
145bb2b058fSMarc-André Lureau
146bb2b058fSMarc-André Lureau return G_SOURCE_CONTINUE;
147bb2b058fSMarc-André Lureau }
148bb2b058fSMarc-André Lureau
fd_chr_add_watch(Chardev * chr,GIOCondition cond)149894593afSMarc-André Lureau static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
150894593afSMarc-André Lureau {
151894593afSMarc-André Lureau FDChardev *s = FD_CHARDEV(chr);
152bb2b058fSMarc-André Lureau g_autoptr(GSource) source = fd_source_new(s);
153bb2b058fSMarc-André Lureau
154bb2b058fSMarc-André Lureau if (s->ioc_out) {
155bb2b058fSMarc-André Lureau g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_out, cond & ~G_IO_IN);
156bb2b058fSMarc-André Lureau g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
157bb2b058fSMarc-André Lureau g_source_add_child_source(source, child);
158bb2b058fSMarc-André Lureau }
159bb2b058fSMarc-André Lureau if (s->ioc_in) {
160bb2b058fSMarc-André Lureau g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_in, cond & ~G_IO_OUT);
161bb2b058fSMarc-André Lureau g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
162bb2b058fSMarc-André Lureau g_source_add_child_source(source, child);
163bb2b058fSMarc-André Lureau }
164bb2b058fSMarc-André Lureau
165bb2b058fSMarc-André Lureau return g_steal_pointer(&source);
166894593afSMarc-André Lureau }
167894593afSMarc-André Lureau
fd_chr_update_read_handler(Chardev * chr)168bb86d05fSPeter Xu static void fd_chr_update_read_handler(Chardev *chr)
169894593afSMarc-André Lureau {
170894593afSMarc-André Lureau FDChardev *s = FD_CHARDEV(chr);
171894593afSMarc-André Lureau
172b19456ddSzhanghailiang remove_fd_in_watch(chr);
173894593afSMarc-André Lureau if (s->ioc_in) {
174b19456ddSzhanghailiang chr->gsource = io_add_watch_poll(chr, s->ioc_in,
175894593afSMarc-André Lureau fd_chr_read_poll,
176894593afSMarc-André Lureau fd_chr_read, chr,
1776bbb6c06SPeter Xu chr->gcontext);
178894593afSMarc-André Lureau }
179894593afSMarc-André Lureau }
180894593afSMarc-André Lureau
char_fd_finalize(Object * obj)181894593afSMarc-André Lureau static void char_fd_finalize(Object *obj)
182894593afSMarc-André Lureau {
183894593afSMarc-André Lureau Chardev *chr = CHARDEV(obj);
184894593afSMarc-André Lureau FDChardev *s = FD_CHARDEV(obj);
185894593afSMarc-André Lureau
186b19456ddSzhanghailiang remove_fd_in_watch(chr);
187894593afSMarc-André Lureau if (s->ioc_in) {
188894593afSMarc-André Lureau object_unref(OBJECT(s->ioc_in));
189894593afSMarc-André Lureau }
190894593afSMarc-André Lureau if (s->ioc_out) {
191894593afSMarc-André Lureau object_unref(OBJECT(s->ioc_out));
192894593afSMarc-André Lureau }
193894593afSMarc-André Lureau
194894593afSMarc-André Lureau qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
195894593afSMarc-André Lureau }
196894593afSMarc-André Lureau
qmp_chardev_open_file_source(char * src,int flags,Error ** errp)197894593afSMarc-André Lureau int qmp_chardev_open_file_source(char *src, int flags, Error **errp)
198894593afSMarc-André Lureau {
199894593afSMarc-André Lureau int fd = -1;
200894593afSMarc-André Lureau
201*8b6aa693SNikita Ivanov fd = RETRY_ON_EINTR(qemu_open_old(src, flags, 0666));
202894593afSMarc-André Lureau if (fd == -1) {
203894593afSMarc-André Lureau error_setg_file_open(errp, errno, src);
204894593afSMarc-André Lureau }
205894593afSMarc-André Lureau return fd;
206894593afSMarc-André Lureau }
207894593afSMarc-André Lureau
208894593afSMarc-André Lureau /* open a character device to a unix fd */
qemu_chr_open_fd(Chardev * chr,int fd_in,int fd_out)209894593afSMarc-André Lureau void qemu_chr_open_fd(Chardev *chr,
210894593afSMarc-André Lureau int fd_in, int fd_out)
211894593afSMarc-André Lureau {
212894593afSMarc-André Lureau FDChardev *s = FD_CHARDEV(chr);
213733ba020SMarc-André Lureau g_autofree char *name = NULL;
214733ba020SMarc-André Lureau
215b84bb4dfSMarc-André Lureau if (fd_out >= 0 && !g_unix_set_fd_nonblocking(fd_out, true, NULL)) {
216b84bb4dfSMarc-André Lureau assert(!"Failed to set FD nonblocking");
217733ba020SMarc-André Lureau }
218733ba020SMarc-André Lureau
219733ba020SMarc-André Lureau if (fd_out == fd_in && fd_in >= 0) {
220733ba020SMarc-André Lureau s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
221733ba020SMarc-André Lureau name = g_strdup_printf("chardev-file-%s", chr->label);
222733ba020SMarc-André Lureau qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
223733ba020SMarc-André Lureau s->ioc_out = QIO_CHANNEL(object_ref(s->ioc_in));
224733ba020SMarc-André Lureau return;
225733ba020SMarc-André Lureau }
226894593afSMarc-André Lureau
22746fe3ff6SMarc-André Lureau if (fd_in >= 0) {
228894593afSMarc-André Lureau s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
229894593afSMarc-André Lureau name = g_strdup_printf("chardev-file-in-%s", chr->label);
230894593afSMarc-André Lureau qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
23146fe3ff6SMarc-André Lureau }
232733ba020SMarc-André Lureau
23346fe3ff6SMarc-André Lureau if (fd_out >= 0) {
234894593afSMarc-André Lureau s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
235733ba020SMarc-André Lureau g_free(name);
236894593afSMarc-André Lureau name = g_strdup_printf("chardev-file-out-%s", chr->label);
237894593afSMarc-André Lureau qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
238894593afSMarc-André Lureau }
23946fe3ff6SMarc-André Lureau }
240894593afSMarc-André Lureau
char_fd_class_init(ObjectClass * oc,void * data)241894593afSMarc-André Lureau static void char_fd_class_init(ObjectClass *oc, void *data)
242894593afSMarc-André Lureau {
243894593afSMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc);
244894593afSMarc-André Lureau
245894593afSMarc-André Lureau cc->chr_add_watch = fd_chr_add_watch;
246894593afSMarc-André Lureau cc->chr_write = fd_chr_write;
247894593afSMarc-André Lureau cc->chr_update_read_handler = fd_chr_update_read_handler;
248894593afSMarc-André Lureau }
249894593afSMarc-André Lureau
250894593afSMarc-André Lureau static const TypeInfo char_fd_type_info = {
251894593afSMarc-André Lureau .name = TYPE_CHARDEV_FD,
252894593afSMarc-André Lureau .parent = TYPE_CHARDEV,
253894593afSMarc-André Lureau .instance_size = sizeof(FDChardev),
254894593afSMarc-André Lureau .instance_finalize = char_fd_finalize,
255894593afSMarc-André Lureau .class_init = char_fd_class_init,
256894593afSMarc-André Lureau .abstract = true,
257894593afSMarc-André Lureau };
258894593afSMarc-André Lureau
register_types(void)259894593afSMarc-André Lureau static void register_types(void)
260894593afSMarc-André Lureau {
261894593afSMarc-André Lureau type_register_static(&char_fd_type_info);
262894593afSMarc-André Lureau }
263894593afSMarc-André Lureau
264894593afSMarc-André Lureau type_init(register_types);
265