From: Corey Minyard <cminy...@mvista.com> The socket code was reporting that a socket connection was connected as soon as the connect call was issued. If the connection failed, it would then report it was not connected. With the reconnect code, it's better to wait until the connection is actually operational before reporting that the socket is connected.
Signed-off-by: Corey Minyard <cminy...@mvista.com> --- qemu-char.c | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index d9838aa..6d6dd36 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2310,9 +2310,10 @@ static CharDriverState *qemu_chr_open_udp(CharDriverState *chr, QemuOpts *opts) typedef struct { GIOChannel *chan, *listen_chan; + int waitsrc; guint listen_tag; int fd, listen_fd; - int connected; + enum { TCP_NOT_CONNECTED, TCP_WAITING_CONNECT, TCP_CONNECTED } state; int max_size; int do_telnetopt; int do_nodelay; @@ -2325,7 +2326,7 @@ static gboolean tcp_chr_accept(GIOChannel *chan, GIOCondition cond, void *opaque static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { TCPCharDriver *s = chr->opaque; - if (s->connected) { + if (s->state == TCP_CONNECTED) { return io_channel_send(s->chan, buf, len); } else { /* XXX: indicate an error ? */ @@ -2337,7 +2338,7 @@ static int tcp_chr_read_poll(void *opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; - if (!s->connected) + if (s->state != TCP_CONNECTED) return 0; s->max_size = qemu_chr_be_can_write(chr); return s->max_size; @@ -2482,7 +2483,7 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) uint8_t buf[READ_BUF_LEN]; int len, size; - if (!s->connected || s->max_size <= 0) { + if (s->state != TCP_CONNECTED || s->max_size <= 0) { return TRUE; } len = sizeof(buf); @@ -2491,7 +2492,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; + s->state = TCP_NOT_CONNECTED; if (s->listen_chan) { s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr); } @@ -2518,17 +2519,48 @@ CharDriverState *qemu_chr_open_eventfd(CharDriverState *chr, int eventfd) } #endif -static void tcp_chr_connect(void *opaque) +static gboolean tcp_wait_connect(GIOChannel *source, + GIOCondition condition, + gpointer opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; - s->connected = 1; + if (s->state != TCP_WAITING_CONNECT) { + return FALSE; + } + if (condition & G_IO_ERR || condition & G_IO_HUP) { + /* The connected failed */ + s->state = TCP_NOT_CONNECTED; + g_io_channel_unref(s->chan); + s->chan = NULL; + closesocket(s->fd); + s->fd = -1; + return FALSE; + } + + s->state = TCP_CONNECTED; if (s->chan) { chr->fd_in_tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, tcp_chr_read, chr); } qemu_chr_be_generic_open(chr); + return FALSE; +} + +static void tcp_chr_connect(void *opaque) +{ + CharDriverState *chr = opaque; + TCPCharDriver *s = chr->opaque; + + s->state = TCP_WAITING_CONNECT; + if (s->chan) { + /* Wait until write becomes ready before reporting connected. */ + s->waitsrc = g_io_add_watch(s->chan, + G_IO_OUT | G_IO_HUP | G_IO_ERR, + tcp_wait_connect, + chr); + } } #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c; @@ -2650,7 +2682,7 @@ static CharDriverState *qemu_chr_open_socket_fd(CharDriverState *chr, s = g_malloc0(sizeof(TCPCharDriver)); - s->connected = 0; + s->state = TCP_NOT_CONNECTED; s->fd = -1; s->listen_fd = -1; s->msgfd = -1; @@ -2695,7 +2727,6 @@ static CharDriverState *qemu_chr_open_socket_fd(CharDriverState *chr, s->do_telnetopt = 1; } } else { - s->connected = 1; s->fd = fd; socket_set_nodelay(fd); s->chan = io_channel_from_socket(s->fd); -- 1.8.3.1