From 69f7b67d55316ab7b28fb904b346943497b856a1 Mon Sep 17 00:00:00 2001
From: Chen Fan <chen.fan.fnst@cn.fujitsu.com>
Date: Tue, 7 Oct 2014 12:07:30 +0800
Subject: [PATCH] migration: add migration_host support for IPv6 address
 without brackets

if specifying migration_host to an Ipv6 address without brackets,
it was resolved to an incorrect address, such as:
    tcp:2001:0DB8::1428:4444,
but the correct address should be:
    tcp:[2001:0DB8::1428]:4444
so we should add brackets when parsing it.

Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com>
---
 src/libvirt_private.syms  |  2 +-
 src/qemu/qemu_migration.c | 49 +++++++++++++++++++++++------------------------
 src/util/virsocketaddr.c  | 19 +++++++++---------
 src/util/virsocketaddr.h  |  2 +-
 tests/sockettest.c        | 32 +++++++++++++++----------------
 5 files changed, 51 insertions(+), 53 deletions(-)

Index: libvirt-1.2.5/src/libvirt_private.syms
===================================================================
--- libvirt-1.2.5.orig/src/libvirt_private.syms
+++ libvirt-1.2.5/src/libvirt_private.syms
@@ -1841,11 +1841,11 @@ virSocketAddrGetIpPrefix;
 virSocketAddrGetPort;
 virSocketAddrGetRange;
 virSocketAddrIsNetmask;
-virSocketAddrIsNumeric;
 virSocketAddrIsPrivate;
 virSocketAddrIsWildcard;
 virSocketAddrMask;
 virSocketAddrMaskByPrefix;
+virSocketAddrNumericFamily;
 virSocketAddrParse;
 virSocketAddrParseIPv4;
 virSocketAddrParseIPv6;
Index: libvirt-1.2.5/src/qemu/qemu_migration.c
===================================================================
--- libvirt-1.2.5.orig/src/qemu/qemu_migration.c
+++ libvirt-1.2.5/src/qemu/qemu_migration.c
@@ -2360,7 +2360,6 @@ qemuMigrationPrepareAny(virQEMUDriverPtr
         if (VIR_STRDUP(migrateFrom, "stdio") < 0)
             goto cleanup;
     } else {
-        virSocketAddr listenAddressSocket;
         bool encloseAddress = false;
         bool hostIPv6Capable = false;
         bool qemuIPv6Capable = false;
@@ -2381,28 +2380,21 @@ qemuMigrationPrepareAny(virQEMUDriverPtr
         virObjectUnref(qemuCaps);
 
         if (listenAddress) {
-            if (virSocketAddrIsNumeric(listenAddress)) {
-                /* listenAddress is numeric IPv4 or IPv6 */
-                if (virSocketAddrParse(&listenAddressSocket, listenAddress, AF_UNSPEC) < 0)
+            if (virSocketAddrNumericFamily(listenAddress) == AF_INET6) {
+                if (!qemuIPv6Capable) {
+                    virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                                   _("qemu isn't capable of IPv6"));
+                    goto cleanup;
+                }
+                if (!hostIPv6Capable) {
+                    virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                                   _("host isn't capable of IPv6"));
                     goto cleanup;
-
-                /* address parsed successfully */
-                if (VIR_SOCKET_ADDR_IS_FAMILY(&listenAddressSocket, AF_INET6)) {
-                    if (!qemuIPv6Capable) {
-                        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                                       _("qemu isn't capable of IPv6"));
-                        goto cleanup;
-                    }
-                    if (!hostIPv6Capable) {
-                        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                                       _("host isn't capable of IPv6"));
-                        goto cleanup;
-                    }
-                    /* IPv6 address must be escaped in brackets on the cmd line */
-                    encloseAddress = true;
                 }
+                /* IPv6 address must be escaped in brackets on the cmd line */
+                encloseAddress = true;
             } else {
-                /* listenAddress is a hostname */
+                /* listenAddress is a hostname or IPv4 */
             }
         } else {
             /* Listen on :: instead of 0.0.0.0 if QEMU understands it
@@ -2661,15 +2653,17 @@ qemuMigrationPrepareDirect(virQEMUDriver
      * to be a correct hostname which refers to the target machine).
      */
     if (uri_in == NULL) {
+        bool encloseAddress = false;
+        const char *incFormat;
+
         if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0)
             goto cleanup;
 
         if (migrateHost != NULL) {
-            if (virSocketAddrIsNumeric(migrateHost) &&
-                virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0)
-                goto cleanup;
+            if (virSocketAddrNumericFamily(migrateHost) == AF_INET6)
+                encloseAddress = true;
 
-           if (VIR_STRDUP(hostname, migrateHost) < 0)
+            if (VIR_STRDUP(hostname, migrateHost) < 0)
                 goto cleanup;
         } else {
             if ((hostname = virGetHostname()) == NULL)
@@ -2689,7 +2683,12 @@ qemuMigrationPrepareDirect(virQEMUDriver
          * new targets accept both syntaxes though.
          */
         /* Caller frees */
-        if (virAsprintf(uri_out, "tcp:%s:%d", hostname, port) < 0)
+        if (encloseAddress)
+            incFormat = "%s:[%s]:%d";
+        else
+            incFormat = "%s:%s:%d";
+
+        if (virAsprintf(uri_out, incFormat, "tcp", hostname, port) < 0)
             goto cleanup;
     } else {
         /* Check the URI starts with "tcp:".  We will escape the
Index: libvirt-1.2.5/src/util/virsocketaddr.c
===================================================================
--- libvirt-1.2.5.orig/src/util/virsocketaddr.c
+++ libvirt-1.2.5/src/util/virsocketaddr.c
@@ -856,26 +856,25 @@ virSocketAddrGetIpPrefix(const virSocket
 }
 
 /**
- * virSocketAddrIsNumeric:
+ * virSocketAddrNumericFamily:
  * @address: address to check
  *
- * Check if passed address is an IP address in numeric format. For
- * instance, for 0.0.0.0 true is returned, for 'examplehost"
- * false is returned.
+ * Check if passed address is an IP address in numeric format. and
+ * return the address family, otherwise return 0.
  *
- * Returns: true if @address is an IP address,
- *          false otherwise
+ * Returns: AF_INET or AF_INET6 if @address is an numeric IP address,
+ *          -1 otherwise.
  */
-bool
-virSocketAddrIsNumeric(const char *address)
+int
+virSocketAddrNumericFamily(const char *address)
 {
     struct addrinfo *res;
     unsigned short family;
 
     if (virSocketAddrParseInternal(&res, address, AF_UNSPEC, false) < 0)
-        return false;
+        return -1;
 
     family = res->ai_addr->sa_family;
     freeaddrinfo(res);
-    return family == AF_INET || family == AF_INET6;
+    return family;
 }
Index: libvirt-1.2.5/src/util/virsocketaddr.h
===================================================================
--- libvirt-1.2.5.orig/src/util/virsocketaddr.h
+++ libvirt-1.2.5/src/util/virsocketaddr.h
@@ -125,5 +125,5 @@ bool virSocketAddrIsPrivate(const virSoc
 
 bool virSocketAddrIsWildcard(const virSocketAddr *addr);
 
-bool virSocketAddrIsNumeric(const char *address);
+int virSocketAddrNumericFamily(const char *address);
 #endif /* __VIR_SOCKETADDR_H__ */
Index: libvirt-1.2.5/tests/sockettest.c
===================================================================
--- libvirt-1.2.5.orig/tests/sockettest.c
+++ libvirt-1.2.5/tests/sockettest.c
@@ -219,19 +219,19 @@ static int testWildcardHelper(const void
     return testWildcard(data->addr, data->pass);
 }
 
-struct testIsNumericData {
+struct testNumericData {
     const char *addr;
-    bool pass;
+    int expected;
 };
 
 static int
-testIsNumericHelper(const void *opaque)
+testNumericHelper(const void *opaque)
 {
-    const struct testIsNumericData *data = opaque;
+    const struct testNumericData *data = opaque;
 
-    if (virSocketAddrIsNumeric(data->addr))
-        return data->pass ? 0 : -1;
-    return data->pass ? -1 : 0;
+    if (virSocketAddrNumericFamily(data->addr) != data->expected)
+        return -1;
+    return 0;
 }
 
 static int
@@ -314,11 +314,11 @@ mymain(void)
             ret = -1;                                                   \
     } while (0)
 
-#define DO_TEST_IS_NUMERIC(addr, pass)                                  \
+#define DO_TEST_NUMERIC_FAMILY(addr, pass)                              \
     do {                                                                \
-        struct testIsNumericData data = { addr, pass};                  \
-        if (virtTestRun("Test isNumeric " addr,                         \
-                       testIsNumericHelper, &data) < 0)                 \
+        struct testNumericData data = { addr, pass };                   \
+        if (virtTestRun("Test Numeric Family" addr,                     \
+                       testNumericHelper, &data) < 0)                   \
             ret = -1;                                                   \
     } while (0)
 
@@ -385,11 +385,11 @@ mymain(void)
     DO_TEST_WILDCARD("1", false);
     DO_TEST_WILDCARD("0.1", false);
 
-    DO_TEST_IS_NUMERIC("0.0.0.0", true);
-    DO_TEST_IS_NUMERIC("::", true);
-    DO_TEST_IS_NUMERIC("1", true);
-    DO_TEST_IS_NUMERIC("::ffff", true);
-    DO_TEST_IS_NUMERIC("examplehost", false);
+    DO_TEST_NUMERIC_FAMILY("0.0.0.0", AF_INET);
+    DO_TEST_NUMERIC_FAMILY("::", AF_INET6);
+    DO_TEST_NUMERIC_FAMILY("1", AF_INET);
+    DO_TEST_NUMERIC_FAMILY("::ffff", AF_INET6);
+    DO_TEST_NUMERIC_FAMILY("examplehost", -1);
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
