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 :|