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-10-28 18:35:54 +0000
commit1e3328b3183aa5ba02c0153e1c3d6e49e218f7d9 (patch)
tree4035e34161847707097a2969e628cb0f3d24346b
parent76fa00b37a1a19f6546c741b27061a49f59e4edf (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.c19
2 files changed, 26 insertions, 4 deletions
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 832b7fead4..b6b2785853 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -65,6 +65,7 @@ struct CharDriverState {
int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
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;
@@ -339,6 +340,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);
CharDriverState *qemu_chr_find(const char *name);
bool chr_is_ringbuf(const CharDriverState *chr);
diff --git a/qemu-char.c b/qemu-char.c
index 8623c70964..6f8bb7abd1 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -235,6 +235,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)
@@ -2676,10 +2681,14 @@ static GSource *tcp_chr_add_watch(CharDriverState *chr, GIOCondition cond)
return g_io_create_watch(s->chan, cond);
}
-static void tcp_chr_disconnect(CharDriverState *chr)
+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,
@@ -2691,6 +2700,7 @@ static void tcp_chr_disconnect(CharDriverState *chr)
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)
@@ -2702,7 +2712,7 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
if (cond & G_IO_HUP) {
/* connection closed */
- tcp_chr_disconnect(chr);
+ tcp_chr_del_client(chr);
return TRUE;
}
@@ -2715,7 +2725,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 */
- tcp_chr_disconnect(chr);
+ tcp_chr_del_client(chr);
} else if (size > 0) {
if (s->do_telnetopt)
tcp_chr_process_IAC_bytes(chr, s, buf, &size);
@@ -2738,7 +2748,7 @@ static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
size = tcp_chr_recv(chr, (void *) buf, len);
if (size == 0) {
/* connection closed */
- tcp_chr_disconnect(chr);
+ tcp_chr_del_client(chr);
}
return size;
@@ -2950,6 +2960,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
chr->get_msgfds = tcp_get_msgfds;
chr->set_msgfds = tcp_set_msgfds;
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 */