
On Tue, Oct 01, 2013 at 11:01:37AM +0200, Ján Tomko wrote:
If IPv6 is enabled on the host, bind to :: with IPV6_V6ONLY disabled to check for ports available on both IPv6 and IPv4. --- src/util/virportallocator.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/src/util/virportallocator.c b/src/util/virportallocator.c index 5b7ad41..246f6cd 100644 --- a/src/util/virportallocator.c +++ b/src/util/virportallocator.c @@ -99,14 +99,25 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa, int ret = -1; size_t i; int fd = -1; + bool ipv6 = virHostHasIPv6();
*port = 0; virObjectLock(pa);
for (i = pa->start; i <= pa->end && !*port; i++) { - int reuse = 1; - struct sockaddr_in addr; + int reuse = 1, v6only = 0; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(i), + .sin_addr.s_addr = htonl(INADDR_ANY) + }; + struct sockaddr_in6 addr6 = { + .sin6_family = AF_INET6, + .sin6_port = htons(i), + .sin6_addr = IN6ADDR_ANY_INIT + }; bool used = false; + int rc;
if (virBitmapGetBit(pa->bitmap, i - pa->start, &used) < 0) { @@ -118,10 +129,7 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa, if (used) continue;
- addr.sin_family = AF_INET; - addr.sin_port = htons(i); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - fd = socket(PF_INET, SOCK_STREAM, 0); + fd = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_STREAM, 0); if (fd < 0) { virReportSystemError(errno, "%s", _("Unable to open test socket")); @@ -134,7 +142,19 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa, goto cleanup; }
- if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only, + sizeof(v6only)) < 0) { + virReportSystemError(errno, "%s", + _("Unable to unset socket IPV6_V6ONLY flag")); + goto cleanup; + } + + if (ipv6) + rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6)); + else + rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
IMHO you could write this code without needing to have any upfront check for whether IPv6 is enabled. Set IPV6_V6ONLY == 1. Then unconditionally try to bind separately on IPv4, and IPv6, and catch the error you'd get back if either IPv4 or IPv6 were disabled on the host. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|