From mboxrd@z Thu Jan 1 00:00:00 1970 From: Amos Kong Subject: [PATCH v3 6/9] net: use getaddrinfo() in tcp_start_common Date: Wed, 07 Mar 2012 06:48:30 +0800 Message-ID: <20120306224830.24264.44283.stgit@dhcp-8-167.nay.redhat.com> References: <20120306224330.24264.9494.stgit@dhcp-8-167.nay.redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit To: aliguori@us.ibm.com, kvm@vger.kernel.org, quintela@redhat.com, jasowang@redhat.com, qemu-devel@nongnu.org, owasserm@redhat.com, laine@redhat.com Return-path: Received: from mx1.redhat.com ([209.132.183.28]:63555 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965280Ab2CFWsf (ORCPT ); Tue, 6 Mar 2012 17:48:35 -0500 In-Reply-To: <20120306224330.24264.9494.stgit@dhcp-8-167.nay.redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: Migrating with IPv6 address exists problem, gethostbyname()/inet_aton() could not translate IPv6 address/port simply, so use getaddrinfo() in tcp_start_common to translate network address and service. We can get an address list by getaddrinfo(). Userlevel IPv6 Programming Introduction: http://www.akkadia.org/drepper/userapi-ipv6.html Reference RFC 3493, Basic Socket Interface Extensions for IPv6 Signed-off-by: Amos Kong --- net.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 58 insertions(+), 21 deletions(-) diff --git a/net.c b/net.c index b05c881..de1db8c 100644 --- a/net.c +++ b/net.c @@ -99,7 +99,7 @@ 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 sockaddr_in *saddr) +static int tcp_server_bind(int fd, struct addrinfo *rp) { int ret; int val = 1; @@ -107,7 +107,7 @@ static int tcp_server_bind(int fd, struct sockaddr_in *saddr) /* allow fast reuse */ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - ret = bind(fd, (struct sockaddr *)saddr, sizeof(*saddr)); + ret = bind(fd, rp->ai_addr, rp->ai_addrlen); if (ret == -1) { ret = -socket_error(); @@ -116,12 +116,12 @@ static int tcp_server_bind(int fd, struct sockaddr_in *saddr) } -static int tcp_client_connect(int fd, struct sockaddr_in *saddr) +static int tcp_client_connect(int fd, struct addrinfo *rp) { int ret; do { - ret = connect(fd, (struct sockaddr *)saddr, sizeof(*saddr)); + ret = connect(fd, rp->ai_addr, rp->ai_addrlen); if (ret == -1) { ret = -socket_error(); } @@ -132,38 +132,75 @@ static int tcp_client_connect(int fd, struct sockaddr_in *saddr) 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; - struct sockaddr_in saddr; *fd = -1; - if (parse_host_port(&saddr, str) < 0) { + service = str; + + if (get_str_sep(hostname, sizeof(hostname), &service, ':') < 0) { error_report("invalid host/port combination: %s", str); return -EINVAL; } - - *fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; + if (server && strlen(hostname) == 0) { + name = NULL; + } else { + name = hostname; } - socket_set_nonblock(*fd); + + /* 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) { - ret = tcp_server_bind(*fd, &saddr); - } else { - ret = tcp_client_connect(*fd, &saddr); + hints.ai_flags = AI_PASSIVE; } -#ifdef _WIN32 - if (ret == -WSAEALREADY || ret == -WSAEINVAL) { - return ret; /* Success */ + s = getaddrinfo(name, service, &hints, &result); + if (s != 0) { + error_report("qemu: getaddrinfo: %s", 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); + } +#ifdef _WIN32 + if (ret == -WSAEALREADY || ret == -WSAEINVAL) { + *fd = sfd; + break; /* Success */ + } #endif - if (ret >= 0 || ret == -EINPROGRESS || ret == -EWOULDBLOCK) { - return ret; /* Success */ + if (ret >= 0 || ret == -EINPROGRESS || ret == -EWOULDBLOCK) { + *fd = sfd; + break; /* Success */ + } + closesocket(sfd); } - closesocket(*fd); + freeaddrinfo(result); return ret; } From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:43682) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S53BN-0003hW-0j for qemu-devel@nongnu.org; Tue, 06 Mar 2012 17:48:38 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S53BK-0005lc-OZ for qemu-devel@nongnu.org; Tue, 06 Mar 2012 17:48:36 -0500 Received: from mx1.redhat.com ([209.132.183.28]:5029) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S53BK-0005lJ-GX for qemu-devel@nongnu.org; Tue, 06 Mar 2012 17:48:34 -0500 From: Amos Kong Date: Wed, 07 Mar 2012 06:48:30 +0800 Message-ID: <20120306224830.24264.44283.stgit@dhcp-8-167.nay.redhat.com> In-Reply-To: <20120306224330.24264.9494.stgit@dhcp-8-167.nay.redhat.com> References: <20120306224330.24264.9494.stgit@dhcp-8-167.nay.redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [PATCH v3 6/9] net: use getaddrinfo() in tcp_start_common List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: aliguori@us.ibm.com, kvm@vger.kernel.org, quintela@redhat.com, jasowang@redhat.com, qemu-devel@nongnu.org, owasserm@redhat.com, laine@redhat.com Migrating with IPv6 address exists problem, gethostbyname()/inet_aton() could not translate IPv6 address/port simply, so use getaddrinfo() in tcp_start_common to translate network address and service. We can get an address list by getaddrinfo(). Userlevel IPv6 Programming Introduction: http://www.akkadia.org/drepper/userapi-ipv6.html Reference RFC 3493, Basic Socket Interface Extensions for IPv6 Signed-off-by: Amos Kong --- net.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 58 insertions(+), 21 deletions(-) diff --git a/net.c b/net.c index b05c881..de1db8c 100644 --- a/net.c +++ b/net.c @@ -99,7 +99,7 @@ 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 sockaddr_in *saddr) +static int tcp_server_bind(int fd, struct addrinfo *rp) { int ret; int val = 1; @@ -107,7 +107,7 @@ static int tcp_server_bind(int fd, struct sockaddr_in *saddr) /* allow fast reuse */ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); - ret = bind(fd, (struct sockaddr *)saddr, sizeof(*saddr)); + ret = bind(fd, rp->ai_addr, rp->ai_addrlen); if (ret == -1) { ret = -socket_error(); @@ -116,12 +116,12 @@ static int tcp_server_bind(int fd, struct sockaddr_in *saddr) } -static int tcp_client_connect(int fd, struct sockaddr_in *saddr) +static int tcp_client_connect(int fd, struct addrinfo *rp) { int ret; do { - ret = connect(fd, (struct sockaddr *)saddr, sizeof(*saddr)); + ret = connect(fd, rp->ai_addr, rp->ai_addrlen); if (ret == -1) { ret = -socket_error(); } @@ -132,38 +132,75 @@ static int tcp_client_connect(int fd, struct sockaddr_in *saddr) 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; - struct sockaddr_in saddr; *fd = -1; - if (parse_host_port(&saddr, str) < 0) { + service = str; + + if (get_str_sep(hostname, sizeof(hostname), &service, ':') < 0) { error_report("invalid host/port combination: %s", str); return -EINVAL; } - - *fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; + if (server && strlen(hostname) == 0) { + name = NULL; + } else { + name = hostname; } - socket_set_nonblock(*fd); + + /* 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) { - ret = tcp_server_bind(*fd, &saddr); - } else { - ret = tcp_client_connect(*fd, &saddr); + hints.ai_flags = AI_PASSIVE; } -#ifdef _WIN32 - if (ret == -WSAEALREADY || ret == -WSAEINVAL) { - return ret; /* Success */ + s = getaddrinfo(name, service, &hints, &result); + if (s != 0) { + error_report("qemu: getaddrinfo: %s", 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); + } +#ifdef _WIN32 + if (ret == -WSAEALREADY || ret == -WSAEINVAL) { + *fd = sfd; + break; /* Success */ + } #endif - if (ret >= 0 || ret == -EINPROGRESS || ret == -EWOULDBLOCK) { - return ret; /* Success */ + if (ret >= 0 || ret == -EINPROGRESS || ret == -EWOULDBLOCK) { + *fd = sfd; + break; /* Success */ + } + closesocket(sfd); } - closesocket(*fd); + freeaddrinfo(result); return ret; }