aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-06-16 18:36:39 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-06-23 16:20:42 +0100
commit3bc96eb653d027d805a8cb59b681f82cff55db64 (patch)
tree5c7c908e7ed7461ac864ff2bb00c576cdf3f211f
parentfceec299c230d5763aacc5d525d6990c2ace51eb (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.h11
-rw-r--r--qemu-char.c39
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 */