diff --git a/lib/cluster/cluster.c b/lib/cluster/cluster.c
index f443c99fa4..a91cad3084 100644
--- a/lib/cluster/cluster.c
+++ b/lib/cluster/cluster.c
@@ -1,658 +1,669 @@
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include <crm_internal.h>
 #include <dlfcn.h>
 
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <time.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
 
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 
 #include <crm/common/ipc.h>
 #include <crm/cluster/internal.h>
 
 CRM_TRACE_INIT_DATA(cluster);
 
 #if SUPPORT_HEARTBEAT
 void *hb_library = NULL;
 #endif
 
 static char *
 get_heartbeat_uuid(const char *uname)
 {
     char *uuid_calc = NULL;
 
 #if SUPPORT_HEARTBEAT
     cl_uuid_t uuid_raw;
     const char *unknown = "00000000-0000-0000-0000-000000000000";
 
     if (heartbeat_cluster == NULL) {
         crm_warn("No connection to heartbeat, using uuid=uname");
         return NULL;
     } else if(uname == NULL) {
         return NULL;
     }
 
     if (heartbeat_cluster->llc_ops->get_uuid_by_name(heartbeat_cluster, uname, &uuid_raw) ==
         HA_FAIL) {
         crm_err("get_uuid_by_name() call failed for host %s", uname);
         free(uuid_calc);
         return NULL;
     }
 
     uuid_calc = calloc(1, 50);
     cl_uuid_unparse(&uuid_raw, uuid_calc);
 
     if (safe_str_eq(uuid_calc, unknown)) {
         crm_warn("Could not calculate UUID for %s", uname);
         free(uuid_calc);
         return NULL;
     }
 #endif
     return uuid_calc;
 }
 
 static gboolean
 uname_is_uuid(void)
 {
     static const char *uuid_pref = NULL;
 
     if (uuid_pref == NULL) {
         uuid_pref = getenv("PCMK_uname_is_uuid");
     }
 
     if (uuid_pref == NULL) {
         /* true is legacy mode */
         uuid_pref = "false";
     }
 
     return crm_is_true(uuid_pref);
 }
 
 int
 get_corosync_id(int id, const char *uuid)
 {
     if (id == 0 && !uname_is_uuid() && is_corosync_cluster()) {
         id = crm_atoi(uuid, "0");
     }
 
     return id;
 }
 
 char *
 get_corosync_uuid(crm_node_t *node)
 {
     if(node == NULL) {
         return NULL;
 
     } else if (!uname_is_uuid() && is_corosync_cluster()) {
         if (node->id > 0) {
             int len = 32;
             char *buffer = NULL;
 
             buffer = calloc(1, (len + 1));
             if (buffer != NULL) {
                 snprintf(buffer, len, "%u", node->id);
             }
 
             return buffer;
 
         } else {
             crm_info("Node %s is not yet known by corosync", node->uname);
         }
 
     } else if (node->uname != NULL) {
         return strdup(node->uname);
     }
 
     return NULL;
 }
 
 const char *
 crm_peer_uuid(crm_node_t *peer)
 {
     char *uuid = NULL;
     enum cluster_type_e type = get_cluster_type();
 
     /* avoid blocking heartbeat calls where possible */
     if(peer == NULL) {
         return NULL;
 
     } else if (peer->uuid) {
         return peer->uuid;
     }
 
     switch (type) {
         case pcmk_cluster_corosync:
             uuid = get_corosync_uuid(peer);
             break;
 
         case pcmk_cluster_cman:
         case pcmk_cluster_classic_ais:
             if (peer->uname) {
                 uuid = strdup(peer->uname);
             }
             break;
 
         case pcmk_cluster_heartbeat:
             uuid = get_heartbeat_uuid(peer->uname);
             break;
 
         case pcmk_cluster_unknown:
         case pcmk_cluster_invalid:
             crm_err("Unsupported cluster type");
             break;
     }
 
     peer->uuid = uuid;
     return peer->uuid;
 }
 
 gboolean
 crm_cluster_connect(crm_cluster_t * cluster)
 {
     enum cluster_type_e type = get_cluster_type();
 
     crm_notice("Connecting to cluster infrastructure: %s", name_for_cluster_type(type));
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         crm_peer_init();
         return init_cs_connection(cluster);
     }
 #endif
 
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         int rv;
 
         /* coverity[var_deref_op] False positive */
         if (cluster->hb_conn == NULL) {
             /* No object passed in, create a new one. */
             ll_cluster_t *(*new_cluster) (const char *llctype) =
                 find_library_function(&hb_library, HEARTBEAT_LIBRARY, "ll_cluster_new", 1);
 
             cluster->hb_conn = (*new_cluster) ("heartbeat");
             /* dlclose(handle); */
 
         } else {
             /* Object passed in. Disconnect first, then reconnect below. */
             cluster->hb_conn->llc_ops->signoff(cluster->hb_conn, FALSE);
         }
 
         /* make sure we are disconnected first with the old object, if any. */
         if (heartbeat_cluster && heartbeat_cluster != cluster->hb_conn) {
             heartbeat_cluster->llc_ops->signoff(heartbeat_cluster, FALSE);
         }
 
         CRM_ASSERT(cluster->hb_conn != NULL);
         heartbeat_cluster = cluster->hb_conn;
 
         rv = register_heartbeat_conn(cluster);
         if (rv) {
             /* we'll benefit from a bigger queue length on heartbeat side.
              * Otherwise, if peers send messages faster than we can consume
              * them right now, heartbeat messaging layer will kick us out once
              * it's (small) default queue fills up :(
              * If we fail to adjust the sendq length, that's not yet fatal, though.
              */
             if (HA_OK != heartbeat_cluster->llc_ops->set_sendq_len(heartbeat_cluster, 1024)) {
                 crm_warn("Cannot set sendq length: %s",
                          heartbeat_cluster->llc_ops->errmsg(heartbeat_cluster));
             }
         }
         return rv;
     }
 #endif
     crm_info("Unsupported cluster stack: %s", getenv("HA_cluster_type"));
     return FALSE;
 }
 
 void
 crm_cluster_disconnect(crm_cluster_t * cluster)
 {
     enum cluster_type_e type = get_cluster_type();
     const char *type_str = name_for_cluster_type(type);
 
     crm_info("Disconnecting from cluster infrastructure: %s", type_str);
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         crm_peer_destroy();
         terminate_cs_connection(cluster);
         crm_info("Disconnected from %s", type_str);
         return;
     }
 #endif
 
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         if (cluster == NULL) {
             crm_info("No cluster connection");
             return;
 
         } else if (cluster->hb_conn) {
             cluster->hb_conn->llc_ops->signoff(cluster->hb_conn, TRUE);
             cluster->hb_conn = NULL;
             crm_info("Disconnected from %s", type_str);
             return;
 
         } else {
             crm_info("No %s connection", type_str);
             return;
         }
     }
 #endif
     crm_info("Unsupported cluster stack: %s", getenv("HA_cluster_type"));
 }
 
 gboolean
 send_cluster_message(crm_node_t * node, enum crm_ais_msg_types service, xmlNode * data,
                      gboolean ordered)
 {
 
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         return send_cluster_message_cs(data, FALSE, node, service);
     }
 #endif
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         return send_ha_message(heartbeat_cluster, data, node ? node->uname : NULL, ordered);
     }
 #endif
     return FALSE;
 }
 
 const char *
 get_local_node_name(void)
 {
     static char *name = NULL;
 
     if(name) {
         return name;
     }
     name = get_node_name(0);
     return name;
 }
 
 char *
 get_node_name(uint32_t nodeid)
 {
     char *name = NULL;
     const char *isolation_host = NULL;
     enum cluster_type_e stack;
 
     if (nodeid == 0) {
         isolation_host = getenv("OCF_RESKEY_"CRM_META"_isolation_host");
         if (isolation_host) {
             return strdup(isolation_host);
         }
     }
 
     stack = get_cluster_type();
     switch (stack) {
         case pcmk_cluster_heartbeat:
             break;
 
 #if SUPPORT_PLUGIN
         case pcmk_cluster_classic_ais:
             name = classic_node_name(nodeid);
             break;
 #else
 #  if SUPPORT_COROSYNC
         case pcmk_cluster_corosync:
             name = corosync_node_name(0, nodeid);
             break;
 #  endif
 #endif
 
 #if SUPPORT_CMAN
         case pcmk_cluster_cman:
             name = cman_node_name(nodeid);
             break;
 #endif
 
         default:
             crm_err("Unknown cluster type: %s (%d)", name_for_cluster_type(stack), stack);
     }
 
     if(name == NULL && nodeid == 0) {
         struct utsname res;
         int rc = uname(&res);
 
         if (rc == 0) {
             crm_notice("Defaulting to uname -n for the local %s node name",
                        name_for_cluster_type(stack));
             name = strdup(res.nodename);
         }
 
         if (name == NULL) {
             crm_err("Could not obtain the local %s node name", name_for_cluster_type(stack));
             crm_exit(DAEMON_RESPAWN_STOP);
         }
     }
 
     if (name == NULL) {
         crm_notice("Could not obtain a node name for %s nodeid %u",
                    name_for_cluster_type(stack), nodeid);
     }
     return name;
 }
 
+/*!
+ * \brief Get the node name corresponding to a node UUID
+ *
+ * \param[in] uuid  UUID of desired node
+ *
+ * \return name of desired node
+ *
+ * \note This relies on the remote peer cache being populated with all
+ *       remote nodes in the cluster, so callers should maintain that cache.
+ */
 const char *
 crm_peer_uname(const char *uuid)
 {
     GHashTableIter iter;
     crm_node_t *node = NULL;
 
     CRM_CHECK(uuid != NULL, return NULL);
 
     /* remote nodes have the same uname and uuid */
     if (g_hash_table_lookup(crm_remote_peer_cache, uuid)) {
         return uuid;
     }
 
     /* avoid blocking calls where possible */
     g_hash_table_iter_init(&iter, crm_peer_cache);
     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
         if(node->uuid && strcasecmp(node->uuid, uuid) == 0) {
             if(node->uname) {
                 return node->uname;
             }
             break;
         }
     }
+    node = NULL;
 
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         if (uname_is_uuid() == FALSE && is_corosync_cluster()) {
             uint32_t id = crm_int_helper(uuid, NULL);
             if(id != 0) {
                 node = crm_find_peer(id, NULL);
             } else {
                 crm_err("Invalid node id: %s", uuid);
             }
 
         } else {
             node = crm_find_peer(0, uuid);
         }
 
         if (node) {
             crm_info("Setting uuid for node %s[%u] to '%s'", node->uname, node->id, uuid);
             node->uuid = strdup(uuid);
             if(node->uname) {
                 return node->uname;
             }
         }
         return NULL;
     }
 #endif
 
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         if (heartbeat_cluster != NULL) {
             cl_uuid_t uuid_raw;
             char *uuid_copy = strdup(uuid);
             char *uname = malloc(MAX_NAME);
 
             cl_uuid_parse(uuid_copy, &uuid_raw);
 
             if (heartbeat_cluster->llc_ops->get_name_by_uuid(heartbeat_cluster, &uuid_raw, uname,
                                                              MAX_NAME) == HA_FAIL) {
                 crm_err("Could not calculate uname for %s", uuid);
             } else {
                 node = crm_get_peer(0, uname);
             }
 
             free(uuid_copy);
             free(uname);
         }
 
         if (node) {
             crm_info("Setting uuid for node %s to '%s'", node->uname, uuid);
             node->uuid = strdup(uuid);
             if(node->uname) {
                 return node->uname;
             }
         }
         return NULL;
     }
 #endif
 
     return NULL;
 }
 
 void
 set_uuid(xmlNode *xml, const char *attr, crm_node_t *node)
 {
     const char *uuid_calc = crm_peer_uuid(node);
 
     crm_xml_add(xml, attr, uuid_calc);
     return;
 }
 
 const char *
 name_for_cluster_type(enum cluster_type_e type)
 {
     switch (type) {
         case pcmk_cluster_classic_ais:
             return "classic openais (with plugin)";
         case pcmk_cluster_cman:
             return "cman";
         case pcmk_cluster_corosync:
             return "corosync";
         case pcmk_cluster_heartbeat:
             return "heartbeat";
         case pcmk_cluster_unknown:
             return "unknown";
         case pcmk_cluster_invalid:
             return "invalid";
     }
     crm_err("Invalid cluster type: %d", type);
     return "invalid";
 }
 
 /* Do not expose these two */
 int set_cluster_type(enum cluster_type_e type);
 static enum cluster_type_e cluster_type = pcmk_cluster_unknown;
 
 int
 set_cluster_type(enum cluster_type_e type)
 {
     if (cluster_type == pcmk_cluster_unknown) {
         crm_info("Cluster type set to: %s", name_for_cluster_type(type));
         cluster_type = type;
         return 0;
 
     } else if (cluster_type == type) {
         return 0;
 
     } else if (pcmk_cluster_unknown == type) {
         cluster_type = type;
         return 0;
     }
 
     crm_err("Cluster type already set to %s, ignoring %s",
             name_for_cluster_type(cluster_type), name_for_cluster_type(type));
     return -1;
 }
 enum cluster_type_e
 get_cluster_type(void)
 {
     bool detected = FALSE;
     const char *cluster = NULL;
 
     /* Return the previous calculation, if any */
     if (cluster_type != pcmk_cluster_unknown) {
         return cluster_type;
     }
 
     cluster = getenv("HA_cluster_type");
 
 #if SUPPORT_HEARTBEAT
     /* If nothing is defined in the environment, try heartbeat (if supported) */
     if(cluster == NULL) {
         ll_cluster_t *hb;
         ll_cluster_t *(*new_cluster) (const char *llctype) = find_library_function(
             &hb_library, HEARTBEAT_LIBRARY, "ll_cluster_new", 1);
 
         hb = (*new_cluster) ("heartbeat");
 
         crm_debug("Testing with Heartbeat");
         /*
          * Test as "casual" client (clientid == NULL; will be replaced by
          * current pid).  We are trying to detect if we can communicate with
          * heartbeat, not if we can register as some specific service.
          * Otherwise all but one of several concurrent invocations will get
          * HA_FAIL because of:
          * WARN: duplicate client add request
          * ERROR: api_process_registration_msg: cannot add client()
          * and then likely fail :(
          */
         if (hb->llc_ops->signon(hb, NULL) == HA_OK) {
             hb->llc_ops->signoff(hb, FALSE);
 
             cluster_type = pcmk_cluster_heartbeat;
             detected = TRUE;
             goto done;
         }
     }
 #endif
 
 #if SUPPORT_COROSYNC
     /* If nothing is defined in the environment, try corosync (if supported) */
     if(cluster == NULL) {
         crm_debug("Testing with Corosync");
         cluster_type = find_corosync_variant();
         if (cluster_type != pcmk_cluster_unknown) {
             detected = TRUE;
             goto done;
         }
     }
 #endif
 
     /* Something was defined in the environment, test it against what we support */
     crm_info("Verifying cluster type: '%s'", cluster?cluster:"-unspecified-");
     if (cluster == NULL) {
 
 #if SUPPORT_HEARTBEAT
     } else if (safe_str_eq(cluster, "heartbeat")) {
         cluster_type = pcmk_cluster_heartbeat;
 #endif
 
 #if SUPPORT_COROSYNC
     } else if (safe_str_eq(cluster, "openais")
                || safe_str_eq(cluster, "classic openais (with plugin)")) {
         cluster_type = pcmk_cluster_classic_ais;
 
     } else if (safe_str_eq(cluster, "corosync")) {
         cluster_type = pcmk_cluster_corosync;
 #endif
 
 #if SUPPORT_CMAN
     } else if (safe_str_eq(cluster, "cman")) {
         cluster_type = pcmk_cluster_cman;
 #endif
 
     } else {
         cluster_type = pcmk_cluster_invalid;
         goto done; /* Keep the compiler happy when no stacks are supported */
     }
 
   done:
     if (cluster_type == pcmk_cluster_unknown) {
         crm_notice("Could not determine the current cluster type");
 
     } else if (cluster_type == pcmk_cluster_invalid) {
         crm_notice("This installation does not support the '%s' cluster infrastructure: terminating.",
                    cluster);
         crm_exit(DAEMON_RESPAWN_STOP);
 
     } else {
         crm_info("%s an active '%s' cluster", detected?"Detected":"Assuming", name_for_cluster_type(cluster_type));
     }
 
     return cluster_type;
 }
 
 gboolean
 is_cman_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_cman;
 }
 
 gboolean
 is_corosync_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_corosync;
 }
 
 gboolean
 is_classic_ais_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_classic_ais;
 }
 
 gboolean
 is_openais_cluster(void)
 {
     enum cluster_type_e type = get_cluster_type();
 
     if (type == pcmk_cluster_classic_ais) {
         return TRUE;
     } else if (type == pcmk_cluster_corosync) {
         return TRUE;
     } else if (type == pcmk_cluster_cman) {
         return TRUE;
     }
     return FALSE;
 }
 
 gboolean
 is_heartbeat_cluster(void)
 {
     return get_cluster_type() == pcmk_cluster_heartbeat;
 }
 
 gboolean
 node_name_is_valid(const char *key, const char *name)
 {
     int octet;
 
     if (name == NULL) {
         crm_trace("%s is empty", key);
         return FALSE;
 
     } else if (sscanf(name, "%d.%d.%d.%d", &octet, &octet, &octet, &octet) == 4) {
         crm_trace("%s contains an ipv4 address, ignoring: %s", key, name);
         return FALSE;
 
     } else if (strstr(name, ":") != NULL) {
         crm_trace("%s contains an ipv6 address, ignoring: %s", key, name);
         return FALSE;
     }
     crm_trace("%s is valid", key);
     return TRUE;
 }