Message ID | 1347348830-10338-1-git-send-email-akong@redhat.com |
---|---|
State | New |
Headers | show |
On 09/11/2012 10:33 AM, Amos Kong wrote: > From: Michael S. Tsirkin <mst@redhat.com> > > getaddrinfo can give us a list of addresses, but we only try to > connect to the first one. If that fails we never proceed to > the next one. This is common on desktop setups that often have ipv6 > configured but not actually working. > > To fix this, refactor address resolution code and make tcp migration > retry connection with a different address. > > This also drops argument from inet_connect. > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com> > Signed-off-by: Amos Kong <akong@redhat.com> > --- > migration-tcp.c | 70 +++++++++++++++++++------ > migration.c | 5 ++ > migration.h | 3 + > nbd.c | 2 +- > qemu-sockets.c | 153 ++++++++++++++++++++++++++++++++++--------------------- > qemu_socket.h | 6 ++- > ui/vnc.c | 2 +- > 7 files changed, 163 insertions(+), 78 deletions(-) > > diff --git a/migration-tcp.c b/migration-tcp.c > index ac891c3..1c1996b 100644 > --- a/migration-tcp.c > +++ b/migration-tcp.c > @@ -30,6 +30,8 @@ > do { } while (0) > #endif > > +static void tcp_wait_for_connect(void *opaque); > + > static int socket_errno(MigrationState *s) > { > return socket_error(); > @@ -53,13 +55,43 @@ static int tcp_close(MigrationState *s) > return r; > } > > +/* > + * Try to connect to next address on list. > + */ > +static void > +tcp_next_connect_migration(MigrationState *s, bool *in_progress, Error **errp) > +{ > + *in_progress = false; > + migrate_fd_retry(s); > + while (s->next_addr) { > + s->fd = inet_connect_addr(s->next_addr, false, in_progress, errp); > + s->next_addr = s->next_addr->ai_next; > + if (*in_progress) { > + qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); > + return; > + } > + } > +} > + Hi, This code is not migration specific, it should be part of qemu-sockets.c. I really don't see a good reason to add next_addr to migration state. I think we need to add a callback for non-blocking connect that is called when the operation is done (it will need the status of the operation), another option is two callback one for success and one for error. I personally would create a separate function inet_connect_nonblocking but that is up to you. Regards, Orit > +static int tcp_connect_done(MigrationState *s) > +{ > + freeaddrinfo(s->addr_list); > + if (s->fd < 0) { > + migrate_fd_error(s); > + return -1; > + } > + > + migrate_fd_connect(s); > + return 0; > +} > + > static void tcp_wait_for_connect(void *opaque) > { > MigrationState *s = opaque; > int val, ret; > + bool in_progress; > socklen_t valsize = sizeof(val); > > - DPRINTF("connect completed\n"); > do { > ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); > } while (ret == -1 && (socket_error()) == EINTR); > @@ -69,39 +101,45 @@ static void tcp_wait_for_connect(void *opaque) > return; > } > > + DPRINTF("connect completed: %d\n", val); > + > qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); > > - if (val == 0) > - migrate_fd_connect(s); > - else { > - DPRINTF("error connecting %d\n", val); > - migrate_fd_error(s); > + if (val != 0) { > + if (!s->next_addr) { > + DPRINTF("all addresses could not be connected\n"); > + freeaddrinfo(s->addr_list); > + migrate_fd_error(s); > + return; > + } > + > + tcp_next_connect_migration(s, &in_progress, NULL); > + if (in_progress) { > + return; > + } > } > + tcp_connect_done(s); > } > > int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, > Error **errp) > { > - bool in_progress; > + bool in_progress = false; > > s->get_error = socket_errno; > s->write = socket_write; > s->close = tcp_close; > + s->next_addr = s->addr_list = inet_parse_connect(host_port, errp); > > - s->fd = inet_connect(host_port, false, &in_progress, errp); > - if (error_is_set(errp)) { > - migrate_fd_error(s); > - return -1; > - } > - > + s->fd = inet_connect_addr(s->next_addr, false, &in_progress, errp); > + s->next_addr = s->next_addr->ai_next; > if (in_progress) { > DPRINTF("connect in progress\n"); > qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); > - } else { > - migrate_fd_connect(s); > + return 0; > } > > - return 0; > + return tcp_connect_done(s); > } > > static void tcp_accept_incoming_migration(void *opaque) > diff --git a/migration.c b/migration.c > index 1edeec5..04c3057 100644 > --- a/migration.c > +++ b/migration.c > @@ -256,6 +256,11 @@ static int migrate_fd_cleanup(MigrationState *s) > return ret; > } > > +int migrate_fd_retry(MigrationState *s) > +{ > + return migrate_fd_cleanup(s); > +} > + > void migrate_fd_error(MigrationState *s) > { > DPRINTF("setting error state\n"); > diff --git a/migration.h b/migration.h > index a9852fc..23eb15f 100644 > --- a/migration.h > +++ b/migration.h > @@ -33,6 +33,8 @@ struct MigrationState > int64_t bandwidth_limit; > QEMUFile *file; > int fd; > + struct addrinfo *addr_list; > + struct addrinfo *next_addr; > int state; > int (*get_error)(MigrationState *s); > int (*close)(MigrationState *s); > @@ -72,6 +74,7 @@ int fd_start_incoming_migration(const char *path); > int fd_start_outgoing_migration(MigrationState *s, const char *fdname); > > void migrate_fd_error(MigrationState *s); > +int migrate_fd_retry(MigrationState *s); > > void migrate_fd_connect(MigrationState *s); > > diff --git a/nbd.c b/nbd.c > index 0dd60c5..417412a 100644 > --- a/nbd.c > +++ b/nbd.c > @@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port) > > int tcp_socket_outgoing_spec(const char *address_and_port) > { > - return inet_connect(address_and_port, true, NULL, NULL); > + return inet_connect(address_and_port, NULL, NULL); > } > > int tcp_socket_incoming(const char *address, uint16_t port) > diff --git a/qemu-sockets.c b/qemu-sockets.c > index 361d890..26d754c 100644 > --- a/qemu-sockets.c > +++ b/qemu-sockets.c > @@ -209,32 +209,24 @@ listen: > return slisten; > } > > -int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) > +static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) > { > - struct addrinfo ai,*res,*e; > + struct addrinfo ai, *res; > + int rc; > const char *addr; > const char *port; > - char uaddr[INET6_ADDRSTRLEN+1]; > - char uport[33]; > - int sock,rc; > - bool block; > > memset(&ai,0, sizeof(ai)); > ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; > ai.ai_family = PF_UNSPEC; > ai.ai_socktype = SOCK_STREAM; > > - if (in_progress) { > - *in_progress = false; > - } > - > addr = qemu_opt_get(opts, "host"); > port = qemu_opt_get(opts, "port"); > - block = qemu_opt_get_bool(opts, "block", 0); > if (addr == NULL || port == NULL) { > fprintf(stderr, "inet_connect: host and/or port not specified\n"); > error_set(errp, QERR_SOCKET_CREATE_FAILED); > - return -1; > + return NULL; > } > > if (qemu_opt_get_bool(opts, "ipv4", 0)) > @@ -247,57 +239,85 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) > fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, > gai_strerror(rc)); > error_set(errp, QERR_SOCKET_CREATE_FAILED); > - return -1; > + return NULL; > } > + return res; > +} > > - for (e = res; e != NULL; e = e->ai_next) { > - if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, > - uaddr,INET6_ADDRSTRLEN,uport,32, > - NI_NUMERICHOST | NI_NUMERICSERV) != 0) { > - fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); > - continue; > - } > - sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); > - if (sock < 0) { > - fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, > - inet_strfamily(e->ai_family), strerror(errno)); > - continue; > +#ifdef _WIN32 > +#define QEMU_SOCKET_RC_INPROGRESS(rc) \ > + ((rc) == -EINPROGRESS || rc == -EWOULDBLOCK || rc == -WSAEALREADY) > +#else > +#define QEMU_SOCKET_RC_INPROGRESS(rc) \ > + ((rc) == -EINPROGRESS) > +#endif > + > +int inet_connect_addr(struct addrinfo *addr, bool block, bool *in_progress, > + Error **errp) > +{ > + char uaddr[INET6_ADDRSTRLEN + 1]; > + char uport[33]; > + int sock, rc; > + > + if (getnameinfo((struct sockaddr *)addr->ai_addr, addr->ai_addrlen, > + uaddr, INET6_ADDRSTRLEN, uport, 32, > + NI_NUMERICHOST | NI_NUMERICSERV)) { > + fprintf(stderr, "%s: getnameinfo: oops\n", __func__); > + return -1; > + } > + sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); > + if (sock < 0) { > + fprintf(stderr, "%s: socket(%s): %s\n", __func__, > + inet_strfamily(addr->ai_family), strerror(errno)); > + return -1; > + } > + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); > + if (!block) { > + socket_set_nonblock(sock); > + } > + /* connect to peer */ > + do { > + rc = 0; > + if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { > + rc = -socket_error(); > } > - setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); > - if (!block) { > - socket_set_nonblock(sock); > + } while (rc == -EINTR); > + > + if (!block && QEMU_SOCKET_RC_INPROGRESS(rc)) { > + if (in_progress) { > + *in_progress = true; > } > - /* connect to peer */ > - do { > - rc = 0; > - if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) { > - rc = -socket_error(); > - } > - } while (rc == -EINTR); > - > - #ifdef _WIN32 > - if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK > - || rc == -WSAEALREADY)) { > - #else > - if (!block && (rc == -EINPROGRESS)) { > - #endif > - if (in_progress) { > - *in_progress = true; > - } > - } else if (rc < 0) { > - if (NULL == e->ai_next) > - fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, > - inet_strfamily(e->ai_family), > - e->ai_canonname, uaddr, uport, strerror(errno)); > - closesocket(sock); > - continue; > + } else if (rc < 0) { > + closesocket(sock); > + return -1; > + } > + return sock; > +} > + > +int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) > +{ > + struct addrinfo *res, *e; > + int sock = -1; > + bool block = qemu_opt_get_bool(opts, "block", 0); > + > + res = inet_parse_connect_opts(opts, errp); > + if (!res) { > + return -1; > + } > + > + if (in_progress) { > + *in_progress = false; > + } > + > + for (e = res; e != NULL; e = e->ai_next) { > + sock = inet_connect_addr(e, block, in_progress, errp); > + if (sock >= 0) { > + break; > } > - freeaddrinfo(res); > - return sock; > } > error_set(errp, QERR_SOCKET_CONNECT_FAILED); > freeaddrinfo(res); > - return -1; > + return sock; > } > > int inet_dgram_opts(QemuOpts *opts) > @@ -493,16 +513,31 @@ int inet_listen(const char *str, char *ostr, int olen, > return sock; > } > > -int inet_connect(const char *str, bool block, bool *in_progress, Error **errp) > +struct addrinfo *inet_parse_connect(const char *str, Error **errp) > +{ > + QemuOpts *opts; > + struct addrinfo *res; > + > + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); > + if (inet_parse(opts, str) == 0) { > + qemu_opt_set(opts, "block", "on"); > + res = inet_parse_connect_opts(opts, errp); > + } else { > + error_set(errp, QERR_SOCKET_CREATE_FAILED); > + res = NULL; > + } > + qemu_opts_del(opts); > + return res; > +} > + > +int inet_connect(const char *str, bool *in_progress, Error **errp) > { > QemuOpts *opts; > int sock = -1; > > opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); > if (inet_parse(opts, str) == 0) { > - if (block) { > - qemu_opt_set(opts, "block", "on"); > - } > + qemu_opt_set(opts, "block", "on"); > sock = inet_connect_opts(opts, in_progress, errp); > } else { > error_set(errp, QERR_SOCKET_CREATE_FAILED); > diff --git a/qemu_socket.h b/qemu_socket.h > index 30ae6af..a69bfb8 100644 > --- a/qemu_socket.h > +++ b/qemu_socket.h > @@ -43,7 +43,11 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); > int inet_listen(const char *str, char *ostr, int olen, > int socktype, int port_offset, Error **errp); > int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp); > -int inet_connect(const char *str, bool block, bool *in_progress, Error **errp); > +struct addrinfo *inet_parse_connect(const char *str, Error **errp); > +int inet_connect_addr(struct addrinfo *addr, bool block, bool *in_progress, > + Error **errp); > + > +int inet_connect(const char *str, bool *in_progress, Error **errp); > int inet_dgram_opts(QemuOpts *opts); > const char *inet_strfamily(int family); > > diff --git a/ui/vnc.c b/ui/vnc.c > index 385e345..5ab8ecc 100644 > --- a/ui/vnc.c > +++ b/ui/vnc.c > @@ -3061,7 +3061,7 @@ int vnc_display_open(DisplayState *ds, const char *display) > if (strncmp(display, "unix:", 5) == 0) > vs->lsock = unix_connect(display+5); > else > - vs->lsock = inet_connect(display, true, NULL, NULL); > + vs->lsock = inet_connect(display, NULL, NULL); > if (-1 == vs->lsock) { > g_free(vs->display); > vs->display = NULL; >
diff --git a/migration-tcp.c b/migration-tcp.c index ac891c3..1c1996b 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -30,6 +30,8 @@ do { } while (0) #endif +static void tcp_wait_for_connect(void *opaque); + static int socket_errno(MigrationState *s) { return socket_error(); @@ -53,13 +55,43 @@ static int tcp_close(MigrationState *s) return r; } +/* + * Try to connect to next address on list. + */ +static void +tcp_next_connect_migration(MigrationState *s, bool *in_progress, Error **errp) +{ + *in_progress = false; + migrate_fd_retry(s); + while (s->next_addr) { + s->fd = inet_connect_addr(s->next_addr, false, in_progress, errp); + s->next_addr = s->next_addr->ai_next; + if (*in_progress) { + qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); + return; + } + } +} + +static int tcp_connect_done(MigrationState *s) +{ + freeaddrinfo(s->addr_list); + if (s->fd < 0) { + migrate_fd_error(s); + return -1; + } + + migrate_fd_connect(s); + return 0; +} + static void tcp_wait_for_connect(void *opaque) { MigrationState *s = opaque; int val, ret; + bool in_progress; socklen_t valsize = sizeof(val); - DPRINTF("connect completed\n"); do { ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); } while (ret == -1 && (socket_error()) == EINTR); @@ -69,39 +101,45 @@ static void tcp_wait_for_connect(void *opaque) return; } + DPRINTF("connect completed: %d\n", val); + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); - if (val == 0) - migrate_fd_connect(s); - else { - DPRINTF("error connecting %d\n", val); - migrate_fd_error(s); + if (val != 0) { + if (!s->next_addr) { + DPRINTF("all addresses could not be connected\n"); + freeaddrinfo(s->addr_list); + migrate_fd_error(s); + return; + } + + tcp_next_connect_migration(s, &in_progress, NULL); + if (in_progress) { + return; + } } + tcp_connect_done(s); } int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp) { - bool in_progress; + bool in_progress = false; s->get_error = socket_errno; s->write = socket_write; s->close = tcp_close; + s->next_addr = s->addr_list = inet_parse_connect(host_port, errp); - s->fd = inet_connect(host_port, false, &in_progress, errp); - if (error_is_set(errp)) { - migrate_fd_error(s); - return -1; - } - + s->fd = inet_connect_addr(s->next_addr, false, &in_progress, errp); + s->next_addr = s->next_addr->ai_next; if (in_progress) { DPRINTF("connect in progress\n"); qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); - } else { - migrate_fd_connect(s); + return 0; } - return 0; + return tcp_connect_done(s); } static void tcp_accept_incoming_migration(void *opaque) diff --git a/migration.c b/migration.c index 1edeec5..04c3057 100644 --- a/migration.c +++ b/migration.c @@ -256,6 +256,11 @@ static int migrate_fd_cleanup(MigrationState *s) return ret; } +int migrate_fd_retry(MigrationState *s) +{ + return migrate_fd_cleanup(s); +} + void migrate_fd_error(MigrationState *s) { DPRINTF("setting error state\n"); diff --git a/migration.h b/migration.h index a9852fc..23eb15f 100644 --- a/migration.h +++ b/migration.h @@ -33,6 +33,8 @@ struct MigrationState int64_t bandwidth_limit; QEMUFile *file; int fd; + struct addrinfo *addr_list; + struct addrinfo *next_addr; int state; int (*get_error)(MigrationState *s); int (*close)(MigrationState *s); @@ -72,6 +74,7 @@ int fd_start_incoming_migration(const char *path); int fd_start_outgoing_migration(MigrationState *s, const char *fdname); void migrate_fd_error(MigrationState *s); +int migrate_fd_retry(MigrationState *s); void migrate_fd_connect(MigrationState *s); diff --git a/nbd.c b/nbd.c index 0dd60c5..417412a 100644 --- a/nbd.c +++ b/nbd.c @@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port) int tcp_socket_outgoing_spec(const char *address_and_port) { - return inet_connect(address_and_port, true, NULL, NULL); + return inet_connect(address_and_port, NULL, NULL); } int tcp_socket_incoming(const char *address, uint16_t port) diff --git a/qemu-sockets.c b/qemu-sockets.c index 361d890..26d754c 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -209,32 +209,24 @@ listen: return slisten; } -int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) +static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) { - struct addrinfo ai,*res,*e; + struct addrinfo ai, *res; + int rc; const char *addr; const char *port; - char uaddr[INET6_ADDRSTRLEN+1]; - char uport[33]; - int sock,rc; - bool block; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; - if (in_progress) { - *in_progress = false; - } - addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); - block = qemu_opt_get_bool(opts, "block", 0); if (addr == NULL || port == NULL) { fprintf(stderr, "inet_connect: host and/or port not specified\n"); error_set(errp, QERR_SOCKET_CREATE_FAILED); - return -1; + return NULL; } if (qemu_opt_get_bool(opts, "ipv4", 0)) @@ -247,57 +239,85 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); error_set(errp, QERR_SOCKET_CREATE_FAILED); - return -1; + return NULL; } + return res; +} - for (e = res; e != NULL; e = e->ai_next) { - if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, - uaddr,INET6_ADDRSTRLEN,uport,32, - NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); - continue; - } - sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); - if (sock < 0) { - fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, - inet_strfamily(e->ai_family), strerror(errno)); - continue; +#ifdef _WIN32 +#define QEMU_SOCKET_RC_INPROGRESS(rc) \ + ((rc) == -EINPROGRESS || rc == -EWOULDBLOCK || rc == -WSAEALREADY) +#else +#define QEMU_SOCKET_RC_INPROGRESS(rc) \ + ((rc) == -EINPROGRESS) +#endif + +int inet_connect_addr(struct addrinfo *addr, bool block, bool *in_progress, + Error **errp) +{ + char uaddr[INET6_ADDRSTRLEN + 1]; + char uport[33]; + int sock, rc; + + if (getnameinfo((struct sockaddr *)addr->ai_addr, addr->ai_addrlen, + uaddr, INET6_ADDRSTRLEN, uport, 32, + NI_NUMERICHOST | NI_NUMERICSERV)) { + fprintf(stderr, "%s: getnameinfo: oops\n", __func__); + return -1; + } + sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (sock < 0) { + fprintf(stderr, "%s: socket(%s): %s\n", __func__, + inet_strfamily(addr->ai_family), strerror(errno)); + return -1; + } + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (!block) { + socket_set_nonblock(sock); + } + /* connect to peer */ + do { + rc = 0; + if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { + rc = -socket_error(); } - setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); - if (!block) { - socket_set_nonblock(sock); + } while (rc == -EINTR); + + if (!block && QEMU_SOCKET_RC_INPROGRESS(rc)) { + if (in_progress) { + *in_progress = true; } - /* connect to peer */ - do { - rc = 0; - if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) { - rc = -socket_error(); - } - } while (rc == -EINTR); - - #ifdef _WIN32 - if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK - || rc == -WSAEALREADY)) { - #else - if (!block && (rc == -EINPROGRESS)) { - #endif - if (in_progress) { - *in_progress = true; - } - } else if (rc < 0) { - if (NULL == e->ai_next) - fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, - inet_strfamily(e->ai_family), - e->ai_canonname, uaddr, uport, strerror(errno)); - closesocket(sock); - continue; + } else if (rc < 0) { + closesocket(sock); + return -1; + } + return sock; +} + +int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) +{ + struct addrinfo *res, *e; + int sock = -1; + bool block = qemu_opt_get_bool(opts, "block", 0); + + res = inet_parse_connect_opts(opts, errp); + if (!res) { + return -1; + } + + if (in_progress) { + *in_progress = false; + } + + for (e = res; e != NULL; e = e->ai_next) { + sock = inet_connect_addr(e, block, in_progress, errp); + if (sock >= 0) { + break; } - freeaddrinfo(res); - return sock; } error_set(errp, QERR_SOCKET_CONNECT_FAILED); freeaddrinfo(res); - return -1; + return sock; } int inet_dgram_opts(QemuOpts *opts) @@ -493,16 +513,31 @@ int inet_listen(const char *str, char *ostr, int olen, return sock; } -int inet_connect(const char *str, bool block, bool *in_progress, Error **errp) +struct addrinfo *inet_parse_connect(const char *str, Error **errp) +{ + QemuOpts *opts; + struct addrinfo *res; + + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + if (inet_parse(opts, str) == 0) { + qemu_opt_set(opts, "block", "on"); + res = inet_parse_connect_opts(opts, errp); + } else { + error_set(errp, QERR_SOCKET_CREATE_FAILED); + res = NULL; + } + qemu_opts_del(opts); + return res; +} + +int inet_connect(const char *str, bool *in_progress, Error **errp) { QemuOpts *opts; int sock = -1; opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); if (inet_parse(opts, str) == 0) { - if (block) { - qemu_opt_set(opts, "block", "on"); - } + qemu_opt_set(opts, "block", "on"); sock = inet_connect_opts(opts, in_progress, errp); } else { error_set(errp, QERR_SOCKET_CREATE_FAILED); diff --git a/qemu_socket.h b/qemu_socket.h index 30ae6af..a69bfb8 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -43,7 +43,11 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset, Error **errp); int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp); -int inet_connect(const char *str, bool block, bool *in_progress, Error **errp); +struct addrinfo *inet_parse_connect(const char *str, Error **errp); +int inet_connect_addr(struct addrinfo *addr, bool block, bool *in_progress, + Error **errp); + +int inet_connect(const char *str, bool *in_progress, Error **errp); int inet_dgram_opts(QemuOpts *opts); const char *inet_strfamily(int family); diff --git a/ui/vnc.c b/ui/vnc.c index 385e345..5ab8ecc 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3061,7 +3061,7 @@ int vnc_display_open(DisplayState *ds, const char *display) if (strncmp(display, "unix:", 5) == 0) vs->lsock = unix_connect(display+5); else - vs->lsock = inet_connect(display, true, NULL, NULL); + vs->lsock = inet_connect(display, NULL, NULL); if (-1 == vs->lsock) { g_free(vs->display); vs->display = NULL;