diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-06-16 18:36:39 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-06-23 16:20:42 +0100 |
commit | 3bc96eb653d027d805a8cb59b681f82cff55db64 (patch) | |
tree | 5c7c908e7ed7461ac864ff2bb00c576cdf3f211f | |
parent | fceec299c230d5763aacc5d525d6990c2ace51eb (diff) |
qemu-char: Add a chr_del_client method to char backends
Add a chr_del_client method to char backends. This makes sense
mostly for TCP, where it means "close the current connection and
then go back to listening for a new one"; the semantics are
as if the remote end had closed the connection.
This could for completeness be supported for other backends
(eg pipe, fd, tty), but this patch only supports it in TCP.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | include/sysemu/char.h | 11 | ||||
-rw-r--r-- | qemu-char.c | 39 |
2 files changed, 40 insertions, 10 deletions
diff --git a/include/sysemu/char.h b/include/sysemu/char.h index b81a6ff185..9be57716b2 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -61,6 +61,7 @@ struct CharDriverState { int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); int (*get_msgfd)(struct CharDriverState *s); int (*chr_add_client)(struct CharDriverState *chr, int fd); + int (*chr_del_client)(struct CharDriverState *chr); IOEventHandler *chr_event; IOCanReadHandler *chr_can_read; IOReadHandler *chr_read; @@ -286,6 +287,16 @@ void qemu_chr_add_handlers(CharDriverState *s, void qemu_chr_be_generic_open(CharDriverState *s); void qemu_chr_accept_input(CharDriverState *s); int qemu_chr_add_client(CharDriverState *s, int fd); + +/** + * @qemu_chr_del_client: + * + * Delete (disconnect) the current client from the char backend, + * as if the remote end had closed itself. This is most useful for TCP + * listening sockets, where it means that we will close the connection to + * the current client but remain listening for new ones. + */ +int qemu_chr_del_client(CharDriverState *s); void qemu_chr_info_print(Monitor *mon, const QObject *ret_data); void qemu_chr_info(Monitor *mon, QObject **ret_data); CharDriverState *qemu_chr_find(const char *name); diff --git a/qemu-char.c b/qemu-char.c index 22ba162ff7..1f4208dad1 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -176,6 +176,11 @@ int qemu_chr_add_client(CharDriverState *s, int fd) return s->chr_add_client ? s->chr_add_client(s, fd) : -1; } +int qemu_chr_del_client(CharDriverState *s) +{ + return s->chr_del_client ? s->chr_del_client(s) : -1; +} + void qemu_chr_accept_input(CharDriverState *s) { if (s->chr_accept_input) @@ -2454,6 +2459,28 @@ static GSource *tcp_chr_add_watch(CharDriverState *chr, GIOCondition cond) return g_io_create_watch(s->chan, cond); } +static int tcp_chr_del_client(CharDriverState *chr) +{ + TCPCharDriver *s = chr->opaque; + + if (!s->connected) { + return -1; + } + + s->connected = 0; + if (s->listen_chan) { + s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, + tcp_chr_accept, chr); + } + remove_fd_in_watch(chr); + g_io_channel_unref(s->chan); + s->chan = NULL; + closesocket(s->fd); + s->fd = -1; + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); + return 0; +} + static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) { CharDriverState *chr = opaque; @@ -2470,16 +2497,7 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) size = tcp_chr_recv(chr, (void *)buf, len); if (size == 0) { /* connection closed */ - s->connected = 0; - if (s->listen_chan) { - s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr); - } - remove_fd_in_watch(chr); - g_io_channel_unref(s->chan); - s->chan = NULL; - closesocket(s->fd); - s->fd = -1; - qemu_chr_be_event(chr, CHR_EVENT_CLOSED); + tcp_chr_del_client(chr); } else if (size > 0) { if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); @@ -2675,6 +2693,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, chr->chr_close = tcp_chr_close; chr->get_msgfd = tcp_get_msgfd; chr->chr_add_client = tcp_chr_add_client; + chr->chr_del_client = tcp_chr_del_client; chr->chr_add_watch = tcp_chr_add_watch; chr->chr_update_read_handler = tcp_chr_update_read_handler; /* be isn't opened until we get a connection */ |