On 05/20/2010 03:57 PM, Chris Lalancette wrote:
We've been running into a lot of situations where
virGetHostname() is returning "localhost", where a plain
gethostname() would have returned the correct thing. This
is because virGetHostname() is *always* trying to canonicalize
the name returned from gethostname(), even when it doesn't
have to.
This patch changes virGetHostname so that if the value returned
from gethostname() is already FQDN or localhost, it returns
that string directly. If the value returned from gethostname()
is a shortened hostname, then we try to canonicalize it. If
that succeeds, we returned the canonicalized hostname. If
that fails, and/or returns "localhost", then we just return
the original string we got from gethostname() and hope for
the best.
Note that after this patch it is up to clients to check whether
"localhost" is an allowed return value. The only place
where it's currently not is in qemu migration.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/libvirt_private.syms | 1 -
src/qemu/qemu_driver.c | 15 +++++--
src/util/util.c | 94 ++++++++++++++++++++++++---------------------
src/util/util.h | 1 -
4 files changed, 60 insertions(+), 51 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 104278f..130a2a1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -653,7 +653,6 @@ virExecDaemonize;
virSetCloseExec;
virSetNonBlock;
virFormatMacAddr;
-virGetHostnameLocalhost;
virGetHostname;
virParseMacAddr;
virFileDeletePid;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0af64c7..cfa5964 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10017,7 +10017,7 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
virDomainDefPtr def = NULL;
virDomainObjPtr vm = NULL;
int this_port;
- char *hostname;
+ char *hostname = NULL;
char migrateFrom [64];
const char *p;
virDomainEventPtr event = NULL;
@@ -10057,9 +10057,15 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
if (port == QEMUD_MIGRATION_NUM_PORTS) port = 0;
/* Get hostname */
- if ((hostname = virGetHostnameLocalhost(0)) == NULL)
+ if ((hostname = virGetHostname(NULL)) == NULL)
goto cleanup;
+ if (STRPREFIX(hostname, "localhost")) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("hostname on destination resolved to localhost, but
migration requires an FQDN"));
+ goto cleanup;
+ }
+
/* XXX this really should have been a properly well-formed
* URI, but we can't add in tcp:// now without breaking
* compatability with old targets. We at least make the
@@ -10067,7 +10073,6 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
*/
/* Caller frees */
internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
- VIR_FREE(hostname);
if (internalret < 0) {
virReportOOMError();
goto cleanup;
@@ -10171,10 +10176,10 @@ endjob:
vm = NULL;
cleanup:
+ VIR_FREE(hostname);
virDomainDefFree(def);
- if (ret != 0) {
+ if (ret != 0)
VIR_FREE(*uri_out);
- }
if (vm)
virDomainObjUnlock(vm);
if (event)
diff --git a/src/util/util.c b/src/util/util.c
index e937d39..930bfac 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2367,11 +2367,31 @@ char *virIndexToDiskName(int idx, const char *prefix)
# define AI_CANONIDN 0
#endif
-char *virGetHostnameLocalhost(int allow_localhost)
+/* Who knew getting a hostname could be so delicate. In Linux (and Unices
+ * in general), many things depend on "hostname" returning a value that will
+ * resolve one way or another. In the modern world where networks frequently
+ * come and go this is often being hard-coded to resolve to "localhost". If
+ * it *doesn't* resolve to localhost, then we would prefer to have the FQDN.
+ * That leads us to 3 possibilities:
+ *
+ * 1) gethostname() returns an FQDN (not localhost) - we return the string
+ * as-is, it's all of the information we want
+ * 2) gethostname() returns "localhost" - we return localhost; doing further
+ * work to try to resolve it is pointless
+ * 3) gethostname() returns a shortened hostname - in this case, we want to
+ * try to resolve this to a fully-qualified name. Therefore we pass it
+ * to getaddrinfo(). There are two possible responses:
+ * a) getaddrinfo() resolves to a FQDN - return the FQDN
+ * b) getaddrinfo() resolves to localhost - in this case, the data we got
+ * from gethostname() is actually more useful than what we got from
+ * getaddrinfo(). Return the value from gethostname() and hope for
+ * the best.
+ */
+char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
Hmm, why isn't one of the fallback options:
if (conn)
hostname = parse_uri(conn.get_uri())
if hostname != "localhost":
return hostname
Seems like if MigratePrepare2 dconn is the remote connection, we are
guaranteed to have a resolvable hostname in the URI (well, resolvable to
the source connection at least).
- Cole