From patchwork Fri Mar 18 13:22:49 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juan Quintela X-Patchwork-Id: 87531 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DDF9BB6FE1 for ; Sat, 19 Mar 2011 00:24:24 +1100 (EST) Received: from localhost ([127.0.0.1]:57960 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q0Zeq-0001vn-5C for incoming@patchwork.ozlabs.org; Fri, 18 Mar 2011 09:24:00 -0400 Received: from [140.186.70.92] (port=45989 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q0Zdv-0001u2-M3 for qemu-devel@nongnu.org; Fri, 18 Mar 2011 09:23:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q0Zdu-0004r4-6V for qemu-devel@nongnu.org; Fri, 18 Mar 2011 09:23:03 -0400 Received: from mx1.redhat.com ([209.132.183.28]:51298) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q0Zdt-0004qo-Qh for qemu-devel@nongnu.org; Fri, 18 Mar 2011 09:23:02 -0400 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p2IDN165001280 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 18 Mar 2011 09:23:01 -0400 Received: from trasno.mitica (ovpn-113-108.phx2.redhat.com [10.3.113.108]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p2IDMudP028014; Fri, 18 Mar 2011 09:23:00 -0400 From: Juan Quintela To: qemu-devel@nongnu.org Date: Fri, 18 Mar 2011 14:22:49 +0100 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 2/3] Use getaddrinfo for migration X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This allows us to use ipv4/ipv6 for migration addresses. Once there, it also uses /etc/services names (it came free). Signed-off-by: Juan Quintela --- migration-tcp.c | 51 +++++++-------------------- net.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu_socket.h | 3 ++ 3 files changed, 122 insertions(+), 38 deletions(-) diff --git a/migration-tcp.c b/migration-tcp.c index 2340b55..2fa496a 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -48,8 +48,6 @@ static int tcp_close(FdMigrationState *s) } return 0; } - - static void tcp_wait_for_connect(void *opaque) { FdMigrationState *s = opaque; @@ -83,13 +81,10 @@ MigrationState *tcp_start_outgoing_migration(Monitor *mon, int blk, int inc) { - struct sockaddr_in addr; FdMigrationState *s; + int fd; int ret; - if (parse_host_port(&addr, host_port) < 0) - return NULL; - s = qemu_mallocz(sizeof(*s)); s->get_error = socket_errno; @@ -105,33 +100,22 @@ MigrationState *tcp_start_outgoing_migration(Monitor *mon, s->state = MIG_STATE_ACTIVE; s->mon = NULL; s->bandwidth_limit = bandwidth_limit; - s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (s->fd == -1) { - qemu_free(s); - return NULL; - } - - socket_set_nonblock(s->fd); if (!detach) { migrate_fd_monitor_suspend(s, mon); } - do { - ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret == -1) - ret = -(s->get_error(s)); - - if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) - qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); - } while (ret == -EINTR); - - if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) { + ret = tcp_client_start(host_port, &fd); + s->fd = fd; + if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) { + DPRINTF("connect in progress"); + qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); + } else if (ret < 0) { DPRINTF("connect failed\n"); migrate_fd_error(s); - } else if (ret >= 0) + } else { migrate_fd_connect(s); - + } return &s->mig_state; } @@ -171,23 +155,14 @@ out2: int tcp_start_incoming_migration(const char *host_port) { - struct sockaddr_in addr; + int ret; int s; - if (parse_host_port(&addr, host_port) < 0) { - fprintf(stderr, "invalid host/port combination: %s\n", host_port); - return -EINVAL; + ret = tcp_server_start(host_port, &s); + if (ret < 0) { + return ret; } - s = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (s == -1) - return -socket_error(); - - socket_set_reuseaddr(s); - - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) - goto err; - if (listen(s, 1) == -1) goto err; diff --git a/net.c b/net.c index ddcca97..4f61cae 100644 --- a/net.c +++ b/net.c @@ -94,6 +94,112 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) return 0; } +static int tcp_server_bind(int fd, struct addrinfo *rp) +{ + int ret; + + socket_set_reuseaddr(fd); + + ret = bind(fd, rp->ai_addr, rp->ai_addrlen); + + if (ret == -1) { + ret = -socket_error(); + } + return ret; + +} + +static int tcp_client_connect(int fd, struct addrinfo *rp) +{ + int ret; + + do { + ret = connect(fd, rp->ai_addr, rp->ai_addrlen); + if (ret == -1) { + ret = -socket_error(); + } + } while (ret == -EINTR); + + return ret; +} + + +static int tcp_start_common(const char *str, int *fd, bool server) +{ + char hostname[512]; + const char *service; + const char *name; + struct addrinfo hints; + struct addrinfo *result, *rp; + int s; + int sfd; + int ret = -EINVAL; + + *fd = -1; + service = str; + if (get_str_sep(hostname, sizeof(hostname), &service, ':') < 0) { + return -EINVAL; + } + if (server && strlen(hostname) == 0) { + name = NULL; + } else { + name = hostname; + } + + /* Obtain address(es) matching host/port */ + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM; /* Datagram socket */ + + if (server) { + hints.ai_flags = AI_PASSIVE; + } + + s = getaddrinfo(name, service, &hints, &result); + if (s != 0) { + fprintf(stderr, "qemu: getaddrinfo: %s\n", gai_strerror(s)); + return -EINVAL; + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully bind/connect). + If socket(2) (or bind/connect(2)) fails, we (close the socket + and) try the next address. */ + + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = qemu_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sfd == -1) { + ret = -errno; + continue; + } + socket_set_nonblock(sfd); + if (server) { + ret = tcp_server_bind(sfd, rp); + } else { + ret = tcp_client_connect(sfd, rp); + } + if (ret >= 0 || ret == -EINPROGRESS || ret == -EWOULDBLOCK) { + *fd = sfd; + break; /* Success */ + } + close(sfd); + } + + freeaddrinfo(result); + return ret; +} + +int tcp_server_start(const char *str, int *fd) +{ + return tcp_start_common(str, fd, true); +} + +int tcp_client_start(const char *str, int *fd) +{ + return tcp_start_common(str, fd, false); +} + int parse_host_port(struct sockaddr_in *saddr, const char *str) { char buf[512]; diff --git a/qemu_socket.h b/qemu_socket.h index f9a7f95..65f7ef0 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -57,4 +57,7 @@ int unix_connect(const char *path); int parse_host_port(struct sockaddr_in *saddr, const char *str); int socket_init(void); +int tcp_client_start(const char *str, int *fd); +int tcp_server_start(const char *str, int *fd); + #endif /* QEMU_SOCKET_H */