aboutsummaryrefslogtreecommitdiff
path: root/qemu-char.c
diff options
context:
space:
mode:
authorNikolay Nikolaev <n.nikolaev@virtualopensystems.com>2014-05-27 15:03:48 +0300
committerMichael S. Tsirkin <mst@redhat.com>2014-06-19 16:41:54 +0300
commit7b0bfdf52d694c9a3a96505aa42ce3f8d63acd35 (patch)
treeba5112e9386ab9cc4372aa5daa6df386a3874e64 /qemu-char.c
parent69e03ae64ba01c4846425fb13e494bce3eedfa6b (diff)
Add chardev API qemu_chr_fe_read_all
This function will attempt to read data from the chardev trying to fill the buffer up to the given length. Add tcp_chr_disconnect to reuse disconnection code where needed. Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com> Signed-off-by: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'qemu-char.c')
-rw-r--r--qemu-char.c83
1 files changed, 73 insertions, 10 deletions
diff --git a/qemu-char.c b/qemu-char.c
index f918f90972..8fb11c8341 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -84,6 +84,7 @@
#include "ui/qemu-spice.h"
#define READ_BUF_LEN 4096
+#define READ_RETRIES 10
/***********************************************************/
/* character device */
@@ -145,6 +146,41 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len)
return offset;
}
+int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len)
+{
+ int offset = 0, counter = 10;
+ int res;
+
+ if (!s->chr_sync_read) {
+ return 0;
+ }
+
+ while (offset < len) {
+ do {
+ res = s->chr_sync_read(s, buf + offset, len - offset);
+ if (res == -1 && errno == EAGAIN) {
+ g_usleep(100);
+ }
+ } while (res == -1 && errno == EAGAIN);
+
+ if (res == 0) {
+ break;
+ }
+
+ if (res < 0) {
+ return res;
+ }
+
+ offset += res;
+
+ if (!counter--) {
+ break;
+ }
+ }
+
+ return offset;
+}
+
int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
{
if (!s->chr_ioctl)
@@ -2454,6 +2490,23 @@ 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)
+{
+ TCPCharDriver *s = chr->opaque;
+
+ 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);
+}
+
static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
{
CharDriverState *chr = opaque;
@@ -2470,16 +2523,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_disconnect(chr);
} else if (size > 0) {
if (s->do_telnetopt)
tcp_chr_process_IAC_bytes(chr, s, buf, &size);
@@ -2490,6 +2534,24 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
return TRUE;
}
+static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ TCPCharDriver *s = chr->opaque;
+ int size;
+
+ if (!s->connected) {
+ return 0;
+ }
+
+ size = tcp_chr_recv(chr, (void *) buf, len);
+ if (size == 0) {
+ /* connection closed */
+ tcp_chr_disconnect(chr);
+ }
+
+ return size;
+}
+
#ifndef _WIN32
CharDriverState *qemu_chr_open_eventfd(int eventfd)
{
@@ -2678,6 +2740,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
chr->opaque = s;
chr->chr_write = tcp_chr_write;
+ chr->chr_sync_read = tcp_chr_sync_read;
chr->chr_close = tcp_chr_close;
chr->get_msgfd = tcp_get_msgfd;
chr->chr_add_client = tcp_chr_add_client;