@@ -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);