Blob Blame History Raw
From 305dad8388ea27b4d1bf1202e90ad6947ae0ab26 Mon Sep 17 00:00:00 2001
From: Pavan Balaji <balaji@anl.gov>
Date: Thu, 21 Jan 2016 17:01:42 -0600
Subject: [PATCH] hydra: improve localhost detection.

Be more forgiving for systems that do not resolve "localhost" or
equivalent names very well (e.g., they are not added to /etc/hosts).
Try them out, and if nothing works, fallback to "is not local" mode.

Thanks to Orion Poplawski <orion@cora.nwra.com> for the suggestion.
---
 src/pm/hydra/utils/sock/sock.c | 89 +++++++++++++++++++++++-------------------
 1 file changed, 48 insertions(+), 41 deletions(-)

diff --git a/src/pm/hydra/utils/sock/sock.c b/src/pm/hydra/utils/sock/sock.c
index 86b25077aac2..dc56c767f544 100644
--- a/src/pm/hydra/utils/sock/sock.c
+++ b/src/pm/hydra/utils/sock/sock.c
@@ -492,7 +492,7 @@ HYD_status HYDU_sock_get_iface_ip(char *iface, char **ip)
 HYD_status HYDU_sock_is_local(char *host, int *is_local)
 {
     struct hostent *ht;
-    char *host_ip = NULL, *local_ip = NULL, *lhost_ip = NULL;
+    char *host_ip = NULL, *lhost_ip = NULL;
     char lhost[MAX_HOSTNAME_LEN];
     struct sockaddr_in sa;
     struct ifaddrs *ifaddr, *ifa;
@@ -516,54 +516,63 @@ HYD_status HYDU_sock_is_local(char *host, int *is_local)
 
     /* STEP 1: If "host" matches the local host name, return */
     if (gethostname(lhost, MAX_HOSTNAME_LEN) < 0) {
-        HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "gethostname returned an error\n");
+        /* We can't figure out what my localhost name is.  *sigh*.  We
+         * could return an error here, but we will just punt it to the
+         * upper layer saying that we don't know if it is local.  We
+         * cannot try steps 2 and 3 either, since we don't have our
+         * local hostname. */
+        goto fn_exit;
     }
     else if (!strcmp(lhost, host)) {
         *is_local = 1;
         goto fn_exit;
     }
+    else {
+        /* we have our local hostname, but that does not match the
+         * provided hostname.  Let's try to get our remote IP address
+         * first.  If we can't get that, we can give up. */
+        /* If we are unable to resolve the remote host name, it need
+         * not be an error. It could mean that the user is using an
+         * alias for the hostname (e.g., an ssh config alias) */
+        if ((ht = gethostbyname(host)) == NULL)
+            goto fn_exit;
 
+        memset((char *) &sa, 0, sizeof(struct sockaddr_in));
+        memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length);
 
-    /* STEP 2: If the IP address associated with "host" and the IP address local
-     * host resolves to match, return */
-
-    if ((ht = gethostbyname(lhost)) == NULL) {
-        HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "gethostbyname error on %s: %s\n",
-                            lhost, hstrerror(h_errno));
+        /* Find the IP address of the host */
+        host_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf,
+                                                 MAX_HOSTNAME_LEN));
+        HYDU_ASSERT(host_ip, status);
     }
 
-    memset((char *) &sa, 0, sizeof(struct sockaddr_in));
-    memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length);
-
-    /* Find the IP address of the host */
-    lhost_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf,
-                                              MAX_HOSTNAME_LEN));
-    HYDU_ASSERT(lhost_ip, status);
+    /* OK, if we are here, we got the remote IP.  We have two ways of
+     * getting the local IP: gethostbyname or getifaddrs.  We'll try
+     * both.  */
 
-    /* If we are unable to resolve the remote host name, it need not be an
-     * error. It could mean that the user is using an alias for the hostname
-     * (e.g., an ssh config alias) */
-    if ((ht = gethostbyname(host)) == NULL)
-        goto fn_exit;
+    /* STEP 2: Let's try the gethostbyname model */
 
-    memset((char *) &sa, 0, sizeof(struct sockaddr_in));
-    memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length);
+    if ((ht = gethostbyname(lhost))) {
+        memset((char *) &sa, 0, sizeof(struct sockaddr_in));
+        memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length);
 
-    /* Find the IP address of the host */
-    host_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf,
-                                             MAX_HOSTNAME_LEN));
-    HYDU_ASSERT(host_ip, status);
+        /* Find the IP address of the host */
+        lhost_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf,
+                                                  MAX_HOSTNAME_LEN));
+        HYDU_ASSERT(lhost_ip, status);
 
-    /* See if the IP address of the hostname we got matches the IP address
-     * to which the local host resolves */
-    if (!strcmp(lhost_ip, host_ip)) {
-        *is_local = 1;
-        goto fn_exit;
+        /* See if the IP address of the hostname we got matches the IP
+         * address to which the local host resolves */
+        if (!strcmp(lhost_ip, host_ip)) {
+            *is_local = 1;
+            goto fn_exit;
+        }
     }
 
+    /* Either gethostbyname didn't resolve or we didn't find a match.
+     * Either way, let's try the getifaddr model. */
 
-    /* STEP 3: Find all local IP addresses and try to match the host IP
-     * with it. */
+    /* STEP 3: Let's try the getifaddr model */
 
     if (getifaddrs(&ifaddr) == -1)
         HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "getifaddrs failed\n");
@@ -573,21 +582,21 @@ HYD_status HYDU_sock_is_local(char *host, int *is_local)
         if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
             struct sockaddr_in *sa_ptr = (struct sockaddr_in *) ifa->ifa_addr;
 
-            local_ip = HYDU_strdup((char *)
+            lhost_ip = HYDU_strdup((char *)
                                    inet_ntop(AF_INET, (const void *) &(sa_ptr->sin_addr), buf,
                                              MAX_HOSTNAME_LEN));
-            HYDU_ASSERT(local_ip, status);
+            HYDU_ASSERT(lhost_ip, status);
 
-            /* STEP 3: For each local IP address, see if it matches the "host"
+            /* For each local IP address, see if it matches the "host"
              * IP address */
-            if (!strcmp(host_ip, local_ip)) {
+            if (!strcmp(host_ip, lhost_ip)) {
                 *is_local = 1;
                 freeifaddrs(ifaddr);
                 goto fn_exit;
             }
 
-            HYDU_FREE(local_ip);
-            local_ip = NULL;
+            HYDU_FREE(lhost_ip);
+            lhost_ip = NULL;
         }
     }
 
@@ -596,8 +605,6 @@ HYD_status HYDU_sock_is_local(char *host, int *is_local)
   fn_exit:
     if (host_ip)
         HYDU_FREE(host_ip);
-    if (local_ip)
-        HYDU_FREE(local_ip);
     if (lhost_ip)
         HYDU_FREE(lhost_ip);
     return status;
-- 
1.9.1