diff --git a/crm/crmd/callbacks.c b/crm/crmd/callbacks.c
index f344b219c5..116b0ed989 100644
--- a/crm/crmd/callbacks.c
+++ b/crm/crmd/callbacks.c
@@ -1,656 +1,664 @@
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU 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 software 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
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <portability.h>
 
 #include <sys/param.h>
 #include <crm/crm.h>
 #include <string.h>
 #include <crmd_fsa.h>
 
 #include <heartbeat.h>
 
 #include <hb_api.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/msg.h>
 #include <crm/cib.h>
 
 #include <crmd.h>
 #include <crmd_messages.h>
 #include <crmd_callbacks.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 GHashTable *crmd_peer_state = NULL;
 
 crm_data_t *find_xml_in_hamessage(const HA_Message * msg);
 void crmd_ha_connection_destroy(gpointer user_data);
 
 /* From join_dc... */
 extern gboolean check_join_state(
 	enum crmd_fsa_state cur_state, const char *source);
 
 
 /* #define MAX_EMPTY_CALLBACKS 20 */
 /* int empty_callbacks = 0; */
 
 #define trigger_fsa(source) crm_debug_3("Triggering FSA: %s", __FUNCTION__); \
 	G_main_set_trigger(source);
 
 gboolean
 crmd_ha_msg_dispatch(ll_cluster_t *cluster_conn, gpointer user_data)
 {
 	IPC_Channel *channel = NULL;
 	gboolean stay_connected = TRUE;
 
 	crm_debug_3("Invoked");
 
 	if(cluster_conn != NULL) {
 		channel = cluster_conn->llc_ops->ipcchan(cluster_conn);
 	}
 	
 	CRM_CHECK(cluster_conn != NULL, ;);
 	CRM_CHECK(channel != NULL, ;);
 	
 	if(channel != NULL && IPC_ISRCONN(channel)) {
 		if(cluster_conn->llc_ops->msgready(cluster_conn) == 0) {
 			crm_debug_2("no message ready yet");
 		}
 		/* invoke the callbacks but dont block */
 		cluster_conn->llc_ops->rcvmsg(cluster_conn, 0);
 	}
 	
 	if (channel == NULL || channel->ch_status != IPC_CONNECT) {
 		if(is_set(fsa_input_register, R_HA_DISCONNECTED) == FALSE) {
 			crm_crit("Lost connection to heartbeat service.");
 		} else {
 			crm_info("Lost connection to heartbeat service.");
 		}
 		trigger_fsa(fsa_source);
 		stay_connected = FALSE;
 	}
     
 	return stay_connected;
 }
 
 void
 crmd_ha_connection_destroy(gpointer user_data)
 {
 	crm_debug_3("Invoked");
 	if(is_set(fsa_input_register, R_HA_DISCONNECTED)) {
 		/* we signed out, so this is expected */
 		crm_info("Heartbeat disconnection complete");
 		return;
 	}
 
 	crm_crit("Lost connection to heartbeat service!");
 	register_fsa_input(C_HA_DISCONNECT, I_ERROR, NULL);	
 	trigger_fsa(fsa_source);
 }
 
 void
 crmd_ha_msg_callback(HA_Message * msg, void* private_data)
 {
 	int level = LOG_DEBUG;
 	ha_msg_input_t *new_input = NULL;
 	oc_node_t *from_node = NULL;
 	
 	const char *from = ha_msg_value(msg, F_ORIG);
 	const char *seq  = ha_msg_value(msg, F_SEQ);
 	const char *op   = ha_msg_value(msg, F_CRM_TASK);
 
 	const char *sys_to   = ha_msg_value(msg, F_CRM_SYS_TO);
 	const char *sys_from = ha_msg_value(msg, F_CRM_SYS_FROM);
 
 	CRM_DEV_ASSERT(from != NULL);
 
 	crm_debug_2("HA[inbound]: %s from %s", op, from);
 
 	if(fsa_membership_copy == NULL) {
 		crm_debug("Ignoring HA messages until we are"
 			  " connected to the CCM (%s op from %s)", op, from);
 		crm_log_message_adv(
 			LOG_MSG, "HA[inbound]: Ignore (No CCM)", msg);
 		return;
 	}
 	
 	from_node = g_hash_table_lookup(fsa_membership_copy->members, from);
 
 	if(from_node == NULL) {
 		if(safe_str_eq(op, CRM_OP_VOTE)) {
 			level = LOG_WARNING;
 
 		} else if(AM_I_DC && safe_str_eq(op, CRM_OP_JOIN_ANNOUNCE)) {
 			level = LOG_WARNING;
 
 		} else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) {
 			level = LOG_WARNING;
 		}
 		crm_log_maybe(level, 
 			   "Ignoring HA message (op=%s) from %s: not in our"
 			   " membership list (size=%d)", op, from,
 			   g_hash_table_size(fsa_membership_copy->members));
 		
 		crm_log_message_adv(LOG_MSG, "HA[inbound]: CCM Discard", msg);
 
 	} else if(safe_str_eq(sys_to, CRM_SYSTEM_DC) && AM_I_DC == FALSE) {
 		crm_debug_2("Ignoring message for the DC [F_SEQ=%s]", seq);
 		return;
 
 	} else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) {
 		if(AM_I_DC && safe_str_neq(from, fsa_our_uname)) {
 			crm_err("Another DC detected: %s (op=%s)", from, op);
 			/* make sure the election happens NOW */
 			level = LOG_WARNING;
 			if(fsa_state != S_ELECTION) {
 				new_input = new_ha_msg_input(msg);
 				register_fsa_error_adv(
 					C_FSA_INTERNAL, I_ELECTION, NULL,
 					new_input, __FUNCTION__);
 			}
 			
 #if 0
 		/* still thinking about this one...
 		 * could create a timing issue if we dont notice the
 		 * election before a new DC is elected.
 		 */
 		} else if(fsa_our_dc != NULL && safe_str_neq(from,fsa_our_dc)){
 			crm_warn("Ignoring message from wrong DC: %s vs. %s ",
 				 from, fsa_our_dc);
 			return;
 #endif
 		} else {
 			crm_debug_2("Processing DC message from %s [F_SEQ=%s]",
 				    from, seq);
 		}
 	}
 
 	if(new_input == NULL) {
 		crm_log_message_adv(LOG_MSG, "HA[inbound]", msg);
 		new_input = new_ha_msg_input(msg);
 		route_message(C_HA_MESSAGE, new_input);
 	}
 
 	delete_ha_msg_input(new_input);
 	trigger_fsa(fsa_source);
 
 	return;
 }
 
 
 
 /*
  * Apparently returning TRUE means "stay connected, keep doing stuff".
  * Returning FALSE means "we're all done, close the connection"
  */
 gboolean
 crmd_ipc_msg_callback(IPC_Channel *client, gpointer user_data)
 {
 	int lpc = 0;
 	HA_Message *msg = NULL;
 	ha_msg_input_t *new_input = NULL;
 	crmd_client_t *curr_client = (crmd_client_t*)user_data;
 	gboolean stay_connected = TRUE;
 	
 	crm_debug_2("Invoked: %s",
 		   curr_client->table_key);
 
 	while(IPC_ISRCONN(client)) {
 		if(client->ops->is_message_pending(client) == 0) {
 			break;
 		}
 
 		msg = msgfromIPC_noauth(client);
 		if (msg == NULL) {
 			crm_info("%s: no message this time",
 				curr_client->table_key);
 			continue;
 		}
 
 		lpc++;
 		new_input = new_ha_msg_input(msg);
 		crm_msg_del(msg);
 		
 		crm_debug_2("Processing msg from %s", curr_client->table_key);
 		crm_log_message_adv(LOG_DEBUG_2, "CRMd[inbound]", new_input->msg);
 		if(crmd_authorize_message(new_input, curr_client)) {
 			route_message(C_IPC_MESSAGE, new_input);
 		}
 		delete_ha_msg_input(new_input);
 		
 		msg = NULL;
 		new_input = NULL;
 
 		if(client->ch_status != IPC_CONNECT) {
 			break;
 		}
 	}
 	
 	crm_debug_2("Processed %d messages", lpc);
     
 	if (client->ch_status != IPC_CONNECT) {
 		stay_connected = FALSE;
 		process_client_disconnect(curr_client);
 	}
 
 	trigger_fsa(fsa_source);
 	return stay_connected;
 }
 
 
 
 extern GCHSource *lrm_source;
 
 gboolean
 lrm_dispatch(IPC_Channel *src_not_used, gpointer user_data)
 {
 	/* ?? src == lrm_channel ?? */
 	ll_lrm_t *lrm = (ll_lrm_t*)user_data;
 	IPC_Channel *lrm_channel = lrm->lrm_ops->ipcchan(lrm);
 
 	crm_debug_3("Invoked");
 	lrm->lrm_ops->rcvmsg(lrm, FALSE);
 
 	if(lrm_channel->ch_status != IPC_CONNECT) {
 		if(is_set(fsa_input_register, R_LRM_CONNECTED)) {
 			crm_crit("LRM Connection failed");
 			register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
 			clear_bit_inplace(fsa_input_register, R_LRM_CONNECTED);
 			
 		} else {
 			crm_info("LRM Connection disconnected");
 		}
 
 		lrm_source = NULL;
 		return FALSE;
 	}
 	return TRUE;
 }
 
 extern gboolean process_lrm_event(lrm_op_t *op);
 
 void
 lrm_op_callback(lrm_op_t* op)
 {
 	CRM_CHECK(op != NULL, return);
 	process_lrm_event(op);
 }
 
 void
 crmd_ha_status_callback(
 	const char *node, const char * status,	void* private_data)
 {
 	crm_data_t *update = NULL;
 	crm_notice("Status update: Node %s now has status [%s]",node,status);
 
 	if(safe_str_eq(status, DEADSTATUS)) {
 		/* this node is taost */
 		update = create_node_state(
 			node, status, XML_BOOLEAN_NO, OFFLINESTATUS,
 			CRMD_STATE_INACTIVE, NULL, TRUE, __FUNCTION__);
-		crm_xml_add(update, XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS);
-
+		if(update) {
+			crm_xml_add(update, XML_CIB_ATTR_REPLACE,
+				    XML_TAG_TRANSIENT_NODEATTRS);
+		}
+		
 	} else if(safe_str_eq(status, ACTIVESTATUS)) {
 		update = create_node_state(
-			node, status, NULL, NULL, NULL, NULL, FALSE, __FUNCTION__);
+			node, status, NULL, NULL, NULL, NULL,
+			FALSE, __FUNCTION__);
 	}
 		
 	if(update != NULL) {
 		/* this change should not be broadcast */
 		fsa_cib_anon_update(
 			XML_CIB_TAG_STATUS, update,
 			cib_inhibit_bcast|cib_scope_local|cib_quorum_override);
 		trigger_fsa(fsa_source);
 		free_xml(update);
+
+	} else {
+		crm_info("Ping node %s is %s", node, status);
 	}
+	
 }
 
 void
 crmd_client_status_callback(const char * node, const char * client,
-		 const char * status, void * private)
+			    const char * status, void * private)
 {
 	const char *join = NULL;
 	crm_data_t *update = NULL;
 	gboolean clear_shutdown = FALSE;
 	
 	crm_debug_3("Invoked");
 	if(safe_str_neq(client, CRM_SYSTEM_CRMD)) {
 		return;
 	}
 
 	if(safe_str_eq(status, JOINSTATUS)){
 		status = ONLINESTATUS;
  		clear_shutdown = TRUE;
 
 	} else if(safe_str_eq(status, LEAVESTATUS)){
 		status = OFFLINESTATUS;
 		join   = CRMD_STATE_INACTIVE;
 /* 		clear_shutdown = TRUE; */
 	}
 	
 	set_bit_inplace(fsa_input_register, R_PEER_DATA);
 	g_hash_table_replace(
 		crmd_peer_state, crm_strdup(node), crm_strdup(status));
 
 	if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
 		return;
 	} else if(fsa_state == S_STOPPING) {
 		return;
 	}
 
 	crm_notice("Status update: Client %s/%s now has status [%s]",
 		   node, client, status);
 
 	if(safe_str_eq(status, ONLINESTATUS)) {
 		/* remove the cached value in case it changed */
 		crm_info("Uncaching UUID for %s", node);
 		unget_uuid(node);
 	}
 	
 	if(safe_str_eq(node, fsa_our_dc) && safe_str_eq(status, OFFLINESTATUS)){
 		/* did our DC leave us */
 		crm_info("Got client status callback - our DC is dead");
 		register_fsa_input(C_CRMD_STATUS_CALLBACK, I_ELECTION, NULL);
 		
 	} else {
 		crm_debug_3("Got client status callback");
 		update = create_node_state(
 			node, NULL, NULL, status, join,
 			NULL, clear_shutdown, __FUNCTION__);
 
 		if(clear_shutdown) {
 			crm_xml_add(update, XML_CIB_ATTR_REPLACE,
 				    XML_TAG_TRANSIENT_NODEATTRS);
 		}
 		
 		/* it is safe to keep these updates on the local node
 		 * each node updates their own CIB
 		 */
 		fsa_cib_anon_update(
 			XML_CIB_TAG_STATUS, update,
 			cib_inhibit_bcast|cib_scope_local|cib_quorum_override);
 
 		free_xml(update);
 
 		if(AM_I_DC && safe_str_eq(status, OFFLINESTATUS)) {
 
 			g_hash_table_remove(confirmed_nodes,  node);
 			g_hash_table_remove(finalized_nodes,  node);
 			g_hash_table_remove(integrated_nodes, node);
 			g_hash_table_remove(welcomed_nodes,   node);
 			
 			check_join_state(fsa_state, __FUNCTION__);
 		}
 	}
 	
 	trigger_fsa(fsa_source);
 }
 
 static void
 crmd_ipc_connection_destroy(gpointer user_data)
 {
 	crmd_client_t *client = user_data;
 
 	if(client == NULL) {
 		crm_debug_4("No client to delete");
 		return;
 	}
 	
 	if(client->client_source != NULL) {
 		crm_debug_4("Deleting %s (%p) from mainloop",
 			    client->uuid, client->client_source);
 		G_main_del_IPC_Channel(client->client_source); 
 		client->client_source = NULL;
 	}
 
 	crm_debug_3("Freeing %s client", client->uuid);
 	crm_free(client->table_key);
 	crm_free(client->sub_sys);
 	crm_free(client->uuid);
 	crm_free(client);
 
 	return;
 }
 
 gboolean
 crmd_client_connect(IPC_Channel *client_channel, gpointer user_data)
 {
 	crm_debug_3("Invoked");
 	if (client_channel == NULL) {
 		crm_err("Channel was NULL");
 
 	} else if (client_channel->ch_status == IPC_DISCONNECT) {
 		crm_err("Channel was disconnected");
 
 	} else {
 		crmd_client_t *blank_client = NULL;
 		crm_debug_3("Channel connected");
 		crm_malloc0(blank_client, sizeof(crmd_client_t));
 	
 		if (blank_client == NULL) {
 			return FALSE;
 		}
 		
 		client_channel->ops->set_recv_qlen(client_channel, 100);
 		client_channel->ops->set_send_qlen(client_channel, 100);
 	
 		blank_client->client_channel = client_channel;
 		blank_client->sub_sys   = NULL;
 		blank_client->uuid      = NULL;
 		blank_client->table_key = NULL;
 	
 		blank_client->client_source =
 			G_main_add_IPC_Channel(
 				G_PRIORITY_LOW, client_channel,
 				FALSE,  crmd_ipc_msg_callback,
 				blank_client, crmd_ipc_connection_destroy);
 	}
     
 	return TRUE;
 }
 
 
 gboolean ccm_dispatch(int fd, gpointer user_data)
 {
 	int rc = 0;
 	oc_ev_t *ccm_token = (oc_ev_t*)user_data;
 	gboolean was_error = FALSE;
 	
 	crm_debug_3("Invoked");
 	rc = oc_ev_handle_event(ccm_token);
 
 	if(rc != 0) {
 		if(is_set(fsa_input_register, R_CCM_DISCONNECTED) == FALSE) {
 			/* we signed out, so this is expected */
 			register_fsa_input(C_CCM_CALLBACK, I_ERROR, NULL);
 			crm_err("CCM connection appears to have failed: rc=%d.",
 				rc);
 		}
 		was_error = TRUE;
 	}
 
 	trigger_fsa(fsa_source);
 	return !was_error;
 }
 
 static gboolean fsa_have_quorum = FALSE;
 
 void 
 crmd_ccm_msg_callback(
 	oc_ed_t event, void *cookie, size_t size, const void *data)
 {
 	int instance = -1;
 	gboolean update_cache = FALSE;
 	struct crmd_ccm_data_s *event_data = NULL;
 	const oc_ev_membership_t *membership = data;
 
 	gboolean update_quorum = FALSE;
 	gboolean trigger_transition = FALSE;
 
 	crm_debug_3("Invoked");
 
 	if(data != NULL) {
 		instance = membership->m_instance;
 	}
 	
 	crm_info("Quorum %s after event=%s (id=%d)", 
 		 ccm_have_quorum(event)?"(re)attained":"lost",
 		 ccm_event_name(event), instance);
 	
 	switch(event) {
 		case OC_EV_MS_NEW_MEMBERSHIP:
 		case OC_EV_MS_INVALID:/* fall through */
 			update_cache = TRUE;
 			update_quorum = TRUE;
 			break;
 		case OC_EV_MS_NOT_PRIMARY:
 #if UNTESTED
 			if(AM_I_DC == FALSE) {
 				break;
 			}
 			/* tell the TE to pretend it had completed and stop */
 			/* side effect: we'll end up in S_IDLE */
 			register_fsa_action(A_TE_HALT, TRUE);
 #endif
 			break;
 		case OC_EV_MS_PRIMARY_RESTORED:
 			fsa_membership_copy->id = instance;
 			if(AM_I_DC && need_transition(fsa_state)) {
 				trigger_transition = TRUE;
 			}
 			break;
 		case OC_EV_MS_EVICTED:
 			update_quorum = TRUE;
 			register_fsa_input(C_FSA_INTERNAL, I_STOP, NULL);
 			crm_err("Shutting down after CCM event: %s",
 				ccm_event_name(event));
 			break;
 		default:
 			crm_err("Unknown CCM event: %d", event);
 	}
 
 	if(update_quorum && ccm_have_quorum(event) == FALSE) {
 		/* did we just loose quorum? */
 		if(fsa_have_quorum && need_transition(fsa_state)) {
 			crm_info("Quorum lost: triggering transition (%s)",
 				 ccm_event_name(event));
 			trigger_transition = TRUE;
 		}
 		fsa_have_quorum = FALSE;
 			
 	} else if(update_quorum)  {
 		crm_debug_2("Updating quorum after event %s",
 			    ccm_event_name(event));
 		fsa_have_quorum = TRUE;
 	}
 
 	if(trigger_transition) {
 		crm_debug_2("Scheduling transition after event %s",
 			    ccm_event_name(event));
 		/* make sure that when we query the CIB that it has
 		 * the changes that triggered the transition
 		 */
 		switch(event) {
 			case OC_EV_MS_NEW_MEMBERSHIP:
 			case OC_EV_MS_INVALID:
 			case OC_EV_MS_PRIMARY_RESTORED:
 				fsa_membership_copy->id = instance;
 				break;
 			default:
 				break;
 		}
 		if(update_cache == FALSE) {
 			/* a stand-alone transition */
 			register_fsa_action(A_TE_CANCEL);
 		}
 	}
 	if(update_cache) {
 		crm_debug_2("Updating cache after event %s",
 			    ccm_event_name(event));
 
 		crm_malloc0(event_data, sizeof(struct crmd_ccm_data_s));
 		if(event_data == NULL) { return; }
 		
 		event_data->event = event;
 		if(data != NULL) {
 			event_data->oc = copy_ccm_oc_data(data);
 		}
 		register_fsa_input_adv(
 			C_CCM_CALLBACK, I_CCM_EVENT, event_data,
 			trigger_transition?A_TE_CANCEL:A_NOTHING,
 			FALSE, __FUNCTION__);
 		
 		if (event_data->oc) {
 			crm_free(event_data->oc);
 			event_data->oc = NULL;
 		}
 		crm_free(event_data);
 	} 
 	
 	oc_ev_callback_done(cookie);
 	return;
 }
 
 void
 crmd_cib_connection_destroy(gpointer user_data)
 {
 	crm_debug_3("Invoked");
 	trigger_fsa(fsa_source);
 
 	if(is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
 		crm_info("Connection to the CIB terminated...");
 		return;
 	}
 
 	/* eventually this will trigger a reconnect, not a shutdown */ 
 	crm_err("Connection to the CIB terminated...");
 	register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
 	clear_bit_inplace(fsa_input_register, R_CIB_CONNECTED);
 	
 	return;
 }
 
 longclock_t fsa_start = 0;
 longclock_t fsa_stop = 0;
 longclock_t fsa_diff = 0;
 
 gboolean
 crm_fsa_trigger(gpointer user_data) 
 {
 	unsigned int fsa_diff_ms = 0;
 	if(fsa_diff_max_ms > 0) {
 		fsa_start = time_longclock();
 	}
 	crm_debug_2("Invoked (queue len: %d)", g_list_length(fsa_message_queue));
 	s_crmd_fsa(C_FSA_INTERNAL);
 	crm_debug_2("Exited  (queue len: %d)", g_list_length(fsa_message_queue));
 	if(fsa_diff_max_ms > 0) {
 		fsa_stop = time_longclock();
 		fsa_diff = sub_longclock(fsa_stop, fsa_start);
 		fsa_diff_ms = longclockto_ms(fsa_diff);
 		if(fsa_diff_ms > fsa_diff_max_ms) {
 			crm_err("FSA took %dms to complete", fsa_diff_ms);
 
 		} else if(fsa_diff_ms > fsa_diff_warn_ms) {
 			crm_warn("FSA took %dms to complete", fsa_diff_ms);
 		}
 		
 	}
 	return TRUE;	
 }
diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c
index 13d6290261..46c3c3496b 100644
--- a/crm/crmd/utils.c
+++ b/crm/crmd/utils.c
@@ -1,1389 +1,1395 @@
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU 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 software 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
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <portability.h>
 
 #include <sys/param.h>
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crmd_fsa.h>
 
 #include <clplumbing/Gmain_timeout.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <signal.h>
 
 #include <heartbeat.h>
 
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
 #include <crm/common/msg.h>
 #include <crmd_messages.h>
 #include <crmd_utils.h>
 
 #include <crm/dmalloc_wrapper.h>
 
 void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy);
 
 /*	A_DC_TIMER_STOP, A_DC_TIMER_START,
  *	A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START
  *	A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START
  */
 enum crmd_fsa_input
 do_timer_control(long long action,
 		   enum crmd_fsa_cause cause,
 		   enum crmd_fsa_state cur_state,
 		   enum crmd_fsa_input current_input,
 		   fsa_data_t *msg_data)
 {
 	gboolean timer_op_ok = TRUE;
 	enum crmd_fsa_input result = I_NULL;
 	
 	if(action & A_DC_TIMER_STOP) {
 		timer_op_ok = crm_timer_stop(election_trigger);
 
 	} else if(action & A_FINALIZE_TIMER_STOP) {
 		timer_op_ok = crm_timer_stop(finalization_timer);
 
 	} else if(action & A_INTEGRATE_TIMER_STOP) {
 		timer_op_ok = crm_timer_stop(integration_timer);
 
 /* 	} else if(action & A_ELECTION_TIMEOUT_STOP) { */
 /* 		timer_op_ok = crm_timer_stop(election_timeout); */
 	}
 
 	/* dont start a timer that wasnt already running */
 	if(action & A_DC_TIMER_START && timer_op_ok) {
 		crm_timer_start(election_trigger);
 		if(AM_I_DC) {
 			/* there can be only one */
 			result = I_ELECTION;
 		}
 		
 	} else if(action & A_FINALIZE_TIMER_START) {
 		crm_timer_start(finalization_timer);
 
 	} else if(action & A_INTEGRATE_TIMER_START) {
 		crm_timer_start(integration_timer);
 
 /* 	} else if(action & A_ELECTION_TIMEOUT_START) { */
 /* 		crm_timer_start(election_timeout); */
 	}
 	
 	return I_NULL;
 }
 
 static const char *
 get_timer_desc(fsa_timer_t *timer) 
 {
 	if(timer == election_trigger) {
 		return "Election Trigger";
 
  	} else if(timer == election_timeout) {
 		return "Election Timeout";
 		
  	} else if(timer == shutdown_escalation_timer) {
 		return "Shutdown Escalation";
 
  	} else if(timer == integration_timer) {
 		return "Integration Timer";
 
  	} else if(timer == finalization_timer) {
 		return "Finalization Timer";
 
  	} else if(timer == wait_timer) {
 		return "Wait Timer";
 
  	} else if(timer == recheck_timer) {
 		return "PEngine Recheck Timer";
 		
 	}	
 	return "Unknown Timer";
 }
 
 gboolean
 crm_timer_popped(gpointer data)
 {
 	fsa_timer_t *timer = (fsa_timer_t *)data;
 
 	if(timer == wait_timer
 	   || timer == recheck_timer
 	   || timer == finalization_timer
 	   || timer == election_trigger) {
 		crm_info("%s (%s) just popped!",
 			get_timer_desc(timer),
 			fsa_input2string(timer->fsa_input));
 		
 	} else {
 		crm_err("%s (%s) just popped!",
 			get_timer_desc(timer),
 			fsa_input2string(timer->fsa_input));
 	}
 
 	if(timer->repeat == FALSE) {
 		crm_timer_stop(timer); /* make it _not_ go off again */
 	}
 	
 	if(timer->fsa_input == I_INTEGRATED) {
 		register_fsa_input_before(
 			C_TIMER_POPPED, timer->fsa_input, NULL);
 
 	} else if(timer->fsa_input == I_PE_CALC
 		  && fsa_state != S_IDLE) {
 		crm_debug("Discarding %s event in state: %s",
 			  fsa_input2string(timer->fsa_input),
 			  fsa_state2string(fsa_state));
 		
 	} else if(timer->fsa_input == I_FINALIZED
 		  && fsa_state != S_FINALIZE_JOIN) {
 		crm_debug("Discarding %s event in state: %s",
 			  fsa_input2string(timer->fsa_input),
 			  fsa_state2string(fsa_state));
 		
 	} else if(timer->fsa_input != I_NULL) {
 		register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL);
 	}
 	
 	crm_debug_3("Triggering FSA: %s", __FUNCTION__);
 	G_main_set_trigger(fsa_source);
 	
 	return TRUE;
 }
 
 gboolean
 crm_timer_start(fsa_timer_t *timer)
 {
 	const char *timer_desc = get_timer_desc(timer);
 
 	if(timer->source_id == 0 && timer->period_ms > 0) {
 		timer->source_id = Gmain_timeout_add(
 			timer->period_ms, timer->callback, (void*)timer);
 		CRM_ASSERT(timer->source_id != 0);
 		crm_debug("Started %s (%s:%dms), src=%d",
 			  timer_desc, fsa_input2string(timer->fsa_input),
 			  timer->period_ms, timer->source_id);
 
 	} else if(timer->period_ms < 0) {
 		crm_err("Tried to start %s (%s:%dms) with a -ve period",
 			  timer_desc, fsa_input2string(timer->fsa_input),
 			  timer->period_ms);
 		
 	} else {
 		crm_debug("%s (%s:%dms) already running: src=%d",
 			  timer_desc, fsa_input2string(timer->fsa_input),
 			  timer->period_ms, timer->source_id);
 		return FALSE;		
 	}
 	return TRUE;
 }
 
 
 gboolean
 crm_timer_stop(fsa_timer_t *timer)
 {
 	const char *timer_desc = get_timer_desc(timer);
 
 	if(timer == NULL) {
 		crm_err("Attempted to stop NULL timer");
 		return FALSE;
 		
 	} else if(timer->source_id != 0) {
 		crm_debug("Stopping %s (%s:%dms), src=%d",
 			  timer_desc, fsa_input2string(timer->fsa_input),
 			  timer->period_ms, timer->source_id);
 		Gmain_timeout_remove(timer->source_id);
 		timer->source_id = 0;
 		
 	} else {
 		crm_debug_2("%s (%s:%dms) already stopped",
 			  timer_desc, fsa_input2string(timer->fsa_input),
 			  timer->period_ms);
 		return FALSE;
 	}
 	return TRUE;
 }
 
 
 long long
 toggle_bit(long long action_list, long long action)
 {
 	crm_debug_5("Toggling bit %.16llx", action);
 	action_list ^= action;
 	crm_debug_5("Result %.16llx", action_list & action);
 	return action_list;
 }
 
 long long
 clear_bit(long long action_list, long long action)
 {
 	unsigned int	level = LOG_DEBUG_5;
 	crm_log_maybe(level, "Clearing bit\t%.16llx", action);
 	
 	/* ensure its set */
 	action_list |= action;
 
 	/* then toggle */
 	action_list = action_list ^ action;
 
 	return action_list;
 }
 
 long long
 set_bit(long long action_list, long long action)
 {
 	unsigned int	level = LOG_DEBUG_5;
 	crm_log_maybe(level, "Setting bit\t%.16llx", action);
 	action_list |= action;
 	return action_list;
 }
 
 
 gboolean
 is_set(long long action_list, long long action)
 {
 	crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
 	return ((action_list & action) == action);
 }
 
 gboolean
 is_set_any(long long action_list, long long action)
 {
 	crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
 	return ((action_list & action) != 0);
 }
 
 const char *
 fsa_input2string(enum crmd_fsa_input input)
 {
 	const char *inputAsText = NULL;
 	
 	switch(input){
 		case I_NULL:
 			inputAsText = "I_NULL";
 			break;
 		case I_CCM_EVENT:
 			inputAsText = "I_CCM_EVENT";
 			break;
 		case I_CIB_OP:
 			inputAsText = "I_CIB_OP";
 			break;
 		case I_CIB_UPDATE:
 			inputAsText = "I_CIB_UPDATE";
 			break;
 		case I_DC_TIMEOUT:
 			inputAsText = "I_DC_TIMEOUT";
 			break;
 		case I_ELECTION:
 			inputAsText = "I_ELECTION";
 			break;
 		case I_PE_CALC:
 			inputAsText = "I_PE_CALC";
 			break;
 		case I_RELEASE_DC:
 			inputAsText = "I_RELEASE_DC";
 			break;
 		case I_ELECTION_DC:
 			inputAsText = "I_ELECTION_DC";
 			break;
 		case I_ERROR:
 			inputAsText = "I_ERROR";
 			break;
 		case I_FAIL:
 			inputAsText = "I_FAIL";
 			break;
 		case I_INTEGRATED:
 			inputAsText = "I_INTEGRATED";
 			break;
 		case I_FINALIZED:
 			inputAsText = "I_FINALIZED";
 			break;
 		case I_NODE_JOIN:
 			inputAsText = "I_NODE_JOIN";
 			break;
 		case I_JOIN_OFFER:
 			inputAsText = "I_JOIN_OFFER";
 			break;
 		case I_JOIN_REQUEST:
 			inputAsText = "I_JOIN_REQUEST";
 			break;
 		case I_JOIN_RESULT:
 			inputAsText = "I_JOIN_RESULT";
 			break;
 		case I_NOT_DC:
 			inputAsText = "I_NOT_DC";
 			break;
 		case I_RECOVERED:
 			inputAsText = "I_RECOVERED";
 			break;
 		case I_RELEASE_FAIL:
 			inputAsText = "I_RELEASE_FAIL";
 			break;
 		case I_RELEASE_SUCCESS:
 			inputAsText = "I_RELEASE_SUCCESS";
 			break;
 		case I_RESTART:
 			inputAsText = "I_RESTART";
 			break;
 		case I_PE_SUCCESS:
 			inputAsText = "I_PE_SUCCESS";
 			break;
 		case I_ROUTER:
 			inputAsText = "I_ROUTER";
 			break;
 		case I_SHUTDOWN:
 			inputAsText = "I_SHUTDOWN";
 			break;
 		case I_STARTUP:
 			inputAsText = "I_STARTUP";
 			break;
 		case I_TE_SUCCESS:
 			inputAsText = "I_TE_SUCCESS";
 			break;
 		case I_STOP:
 			inputAsText = "I_STOP";
 			break;
 		case I_DC_HEARTBEAT:
 			inputAsText = "I_DC_HEARTBEAT";
 			break;
 		case I_WAIT_FOR_EVENT:
 			inputAsText = "I_WAIT_FOR_EVENT";
 			break;
 		case I_LRM_EVENT:
 			inputAsText = "I_LRM_EVENT";
 			break;
 		case I_PENDING:
 			inputAsText = "I_PENDING";
 			break;
 		case I_HALT:
 			inputAsText = "I_HALT";
 			break;
 		case I_TERMINATE:
 			inputAsText = "I_TERMINATE";
 			break;
 		case I_ILLEGAL:
 			inputAsText = "I_ILLEGAL";
 			break;
 	}
 
 	if(inputAsText == NULL) {
 		crm_err("Input %d is unknown", input);
 		inputAsText = "<UNKNOWN_INPUT>";
 	}
 	
 	return inputAsText;
 }
 
 const char *
 fsa_state2string(enum crmd_fsa_state state)
 {
 	const char *stateAsText = NULL;
 	
 	switch(state){
 		case S_IDLE:
 			stateAsText = "S_IDLE";
 			break;
 		case S_ELECTION:
 			stateAsText = "S_ELECTION";
 			break;
 		case S_INTEGRATION:
 			stateAsText = "S_INTEGRATION";
 			break;
 		case S_FINALIZE_JOIN:
 			stateAsText = "S_FINALIZE_JOIN";
 			break;
 		case S_NOT_DC:
 			stateAsText = "S_NOT_DC";
 			break;
 		case S_POLICY_ENGINE:
 			stateAsText = "S_POLICY_ENGINE";
 			break;
 		case S_RECOVERY:
 			stateAsText = "S_RECOVERY";
 			break;
 		case S_RELEASE_DC:
 			stateAsText = "S_RELEASE_DC";
 			break;
 		case S_PENDING:
 			stateAsText = "S_PENDING";
 			break;
 		case S_STOPPING:
 			stateAsText = "S_STOPPING";
 			break;
 		case S_TERMINATE:
 			stateAsText = "S_TERMINATE";
 			break;
 		case S_TRANSITION_ENGINE:
 			stateAsText = "S_TRANSITION_ENGINE";
 			break;
 		case S_STARTING:
 			stateAsText = "S_STARTING";
 			break;
 		case S_HALT:
 			stateAsText = "S_HALT";
 			break;
 		case S_ILLEGAL:
 			stateAsText = "S_ILLEGAL";
 			break;
 	}
 
 	if(stateAsText == NULL) {
 		crm_err("State %d is unknown", state);
 		stateAsText = "<UNKNOWN_STATE>";
 	}
 	
 	return stateAsText;
 }
 
 const char *
 fsa_cause2string(enum crmd_fsa_cause cause)
 {
 	const char *causeAsText = NULL;
 	
 	switch(cause){
 		case C_UNKNOWN:
 			causeAsText = "C_UNKNOWN";
 			break;
 		case C_STARTUP:
 			causeAsText = "C_STARTUP";
 			break;
 		case C_IPC_MESSAGE:
 			causeAsText = "C_IPC_MESSAGE";
 			break;
 		case C_HA_MESSAGE:
 			causeAsText = "C_HA_MESSAGE";
 			break;
 		case C_CCM_CALLBACK:
 			causeAsText = "C_CCM_CALLBACK";
 			break;
 		case C_TIMER_POPPED:
 			causeAsText = "C_TIMER_POPPED";
 			break;
 		case C_SHUTDOWN:
 			causeAsText = "C_SHUTDOWN";
 			break;
 		case C_HEARTBEAT_FAILED:
 			causeAsText = "C_HEARTBEAT_FAILED";
 			break;
 		case C_SUBSYSTEM_CONNECT:
 			causeAsText = "C_SUBSYSTEM_CONNECT";
 			break;
 		case C_LRM_OP_CALLBACK:
 			causeAsText = "C_LRM_OP_CALLBACK";
 			break;
 		case C_LRM_MONITOR_CALLBACK:
 			causeAsText = "C_LRM_MONITOR_CALLBACK";
 			break;
 		case C_CRMD_STATUS_CALLBACK:
 			causeAsText = "C_CRMD_STATUS_CALLBACK";
 			break;
 		case C_HA_DISCONNECT:
 			causeAsText = "C_HA_DISCONNECT";
 			break;
 		case C_FSA_INTERNAL:
 			causeAsText = "C_FSA_INTERNAL";
 			break;
 		case C_ILLEGAL:
 			causeAsText = "C_ILLEGAL";
 			break;
 	}
 
 	if(causeAsText == NULL) {
 		crm_err("Cause %d is unknown", cause);
 		causeAsText = "<UNKNOWN_CAUSE>";
 	}
 	
 	return causeAsText;
 }
 
 const char *
 fsa_action2string(long long action)
 {
 	const char *actionAsText = NULL;
 	
 	switch(action){
 
 		case A_NOTHING:
 			actionAsText = "A_NOTHING";
 			break;
 		case A_ELECTION_START:
 			actionAsText = "A_ELECTION_START";
 			break;
 		case A_READCONFIG:
 			actionAsText = "A_READCONFIG";
 			break;
 		case O_RELEASE:
 			actionAsText = "O_RELEASE";
 			break;
 		case A_STARTUP:
 			actionAsText = "A_STARTUP";
 			break;
 		case A_STARTED:
 			actionAsText = "A_STARTED";
 			break;
 		case A_HA_CONNECT:
 			actionAsText = "A_HA_CONNECT";
 			break;
 		case A_HA_DISCONNECT:
 			actionAsText = "A_HA_DISCONNECT";
 			break;
 		case A_LRM_CONNECT:
 			actionAsText = "A_LRM_CONNECT";
 			break;
 		case A_LRM_EVENT:
 			actionAsText = "A_LRM_EVENT";
 			break;
 		case A_LRM_INVOKE:
 			actionAsText = "A_LRM_INVOKE";
 			break;
 		case A_LRM_DISCONNECT:
 			actionAsText = "A_LRM_DISCONNECT";
 			break;
 		case A_CL_JOIN_QUERY:
 			actionAsText = "A_CL_JOIN_QUERY";
 			break;
 		case A_DC_TIMER_STOP:
 			actionAsText = "A_DC_TIMER_STOP";
 			break;
 		case A_DC_TIMER_START:
 			actionAsText = "A_DC_TIMER_START";
 			break;
 		case A_INTEGRATE_TIMER_START:
 			actionAsText = "A_INTEGRATE_TIMER_START";
 			break;
 		case A_INTEGRATE_TIMER_STOP:
 			actionAsText = "A_INTEGRATE_TIMER_STOP";
 			break;
 		case A_FINALIZE_TIMER_START:
 			actionAsText = "A_FINALIZE_TIMER_START";
 			break;
 		case A_FINALIZE_TIMER_STOP:
 			actionAsText = "A_FINALIZE_TIMER_STOP";
 			break;
 		case A_ELECTION_COUNT:
 			actionAsText = "A_ELECTION_COUNT";
 			break;
 		case A_ELECTION_VOTE:
 			actionAsText = "A_ELECTION_VOTE";
 			break;
 		case A_ELECTION_CHECK:
 			actionAsText = "A_ELECTION_CHECK";
 			break;
 		case A_CL_JOIN_ANNOUNCE:
 			actionAsText = "A_CL_JOIN_ANNOUNCE";
 			break;
 		case A_CL_JOIN_REQUEST:
 			actionAsText = "A_CL_JOIN_REQUEST";
 			break;
 		case A_CL_JOIN_RESULT:
 			actionAsText = "A_CL_JOIN_RESULT";
 			break;
 		case A_DC_JOIN_OFFER_ALL:
 			actionAsText = "A_DC_JOIN_OFFER_ALL";
 			break;
 		case A_DC_JOIN_OFFER_ONE:
 			actionAsText = "A_DC_JOIN_OFFER_ONE";
 			break;
 		case A_DC_JOIN_PROCESS_REQ:
 			actionAsText = "A_DC_JOIN_PROCESS_REQ";
 			break;
 		case A_DC_JOIN_PROCESS_ACK:
 			actionAsText = "A_DC_JOIN_PROCESS_ACK";
 			break;
 		case A_DC_JOIN_FINALIZE:
 			actionAsText = "A_DC_JOIN_FINALIZE";
 			break;
 		case A_MSG_PROCESS:
 			actionAsText = "A_MSG_PROCESS";
 			break;
 		case A_MSG_ROUTE:
 			actionAsText = "A_MSG_ROUTE";
 			break;
 		case A_RECOVER:
 			actionAsText = "A_RECOVER";
 			break;
 		case A_DC_RELEASE:
 			actionAsText = "A_DC_RELEASE";
 			break;
 		case A_DC_RELEASED:
 			actionAsText = "A_DC_RELEASED";
 			break;
 		case A_DC_TAKEOVER:
 			actionAsText = "A_DC_TAKEOVER";
 			break;
 		case A_SHUTDOWN:
 			actionAsText = "A_SHUTDOWN";
 			break;
 		case A_SHUTDOWN_REQ:
 			actionAsText = "A_SHUTDOWN_REQ";
 			break;
 		case A_STOP:
 			actionAsText = "A_STOP  ";
 			break;
 		case A_EXIT_0:
 			actionAsText = "A_EXIT_0";
 			break;
 		case A_EXIT_1:
 			actionAsText = "A_EXIT_1";
 			break;
 		case A_CCM_CONNECT:
 			actionAsText = "A_CCM_CONNECT";
 			break;
 		case A_CCM_DISCONNECT:
 			actionAsText = "A_CCM_DISCONNECT";
 			break;
 		case A_CCM_EVENT:
 			actionAsText = "A_CCM_EVENT";
 			break;
 		case A_CCM_UPDATE_CACHE:
 			actionAsText = "A_CCM_UPDATE_CACHE";
 			break;
 		case A_CIB_BUMPGEN:
 			actionAsText = "A_CIB_BUMPGEN";
 			break;
 		case A_CIB_INVOKE:
 			actionAsText = "A_CIB_INVOKE";
 			break;
 		case O_CIB_RESTART:
 			actionAsText = "O_CIB_RESTART";
 			break;
 		case A_CIB_START:
 			actionAsText = "A_CIB_START";
 			break;
 		case A_CIB_STOP:
 			actionAsText = "A_CIB_STOP";
 			break;
 		case A_TE_INVOKE:
 			actionAsText = "A_TE_INVOKE";
 			break;
 		case O_TE_RESTART:
 			actionAsText = "O_TE_RESTART";
 			break;
 		case A_TE_START:
 			actionAsText = "A_TE_START";
 			break;
 		case A_TE_STOP:
 			actionAsText = "A_TE_STOP";
 			break;
 		case A_TE_HALT:
 			actionAsText = "A_TE_HALT";
 			break;
 		case A_TE_CANCEL:
 			actionAsText = "A_TE_CANCEL";
 			break;
 		case A_PE_INVOKE:
 			actionAsText = "A_PE_INVOKE";
 			break;
 		case O_PE_RESTART:
 			actionAsText = "O_PE_RESTART";
 			break;
 		case A_PE_START:
 			actionAsText = "A_PE_START";
 			break;
 		case A_PE_STOP:
 			actionAsText = "A_PE_STOP";
 			break;
 		case A_NODE_BLOCK:
 			actionAsText = "A_NODE_BLOCK";
 			break;
 		case A_UPDATE_NODESTATUS:
 			actionAsText = "A_UPDATE_NODESTATUS";
 			break;
 		case A_LOG:
 			actionAsText = "A_LOG   ";
 			break;
 		case A_ERROR:
 			actionAsText = "A_ERROR ";
 			break;
 		case A_WARN:
 			actionAsText = "A_WARN  ";
 			break;
 	}
 
 	if(actionAsText == NULL) {
 		crm_err("Action %.16llx is unknown", action);
 		actionAsText = "<UNKNOWN_ACTION>";
 	}
 	
 	return actionAsText;
 }
 
 
 
 void
 fsa_dump_inputs(int log_level, const char *text, long long input_register)
 {
 	if(input_register == A_NOTHING) {
 		return;
 	}
 	if(text == NULL) {
 		text = "Input register contents:";
 	}
 
 	if(is_set(input_register, R_THE_DC)) {
 		crm_log_maybe(log_level,
 			   "%s %.16llx (R_THE_DC)", text, R_THE_DC);
 	}
 	if(is_set(input_register, R_STARTING)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_STARTING)",
 			      text, R_STARTING);
 	}
 	if(is_set(input_register, R_SHUTDOWN)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_SHUTDOWN)",
 			      text, R_SHUTDOWN);
 	}
 	if(is_set(input_register, R_STAYDOWN)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_STAYDOWN)",
 			      text, R_STAYDOWN);
 	}
 	if(is_set(input_register, R_JOIN_OK)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_JOIN_OK)",
 			      text, R_JOIN_OK);
 	}
 	if(is_set(input_register, R_READ_CONFIG)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_READ_CONFIG)",
 			      text, R_READ_CONFIG);
 	}
 	if(is_set(input_register, R_INVOKE_PE)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_INVOKE_PE)",
 			      text, R_INVOKE_PE);
 	}
 	if(is_set(input_register, R_CIB_CONNECTED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_CIB_CONNECTED)",
 			      text, R_CIB_CONNECTED);
 	}
 	if(is_set(input_register, R_PE_CONNECTED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_PE_CONNECTED)",
 			      text, R_PE_CONNECTED);
 	}
 	if(is_set(input_register, R_TE_CONNECTED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_TE_CONNECTED)",
 			      text, R_TE_CONNECTED);
 	}
 	if(is_set(input_register, R_LRM_CONNECTED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_LRM_CONNECTED)",
 			      text, R_LRM_CONNECTED);
 	}
 	if(is_set(input_register, R_CIB_REQUIRED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_CIB_REQUIRED)",
 			      text, R_CIB_REQUIRED);
 	}
 	if(is_set(input_register, R_PE_REQUIRED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_PE_REQUIRED)",
 			      text, R_PE_REQUIRED);
 	}
 	if(is_set(input_register, R_TE_REQUIRED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_TE_REQUIRED)",
 			      text, R_TE_REQUIRED);
 	}
 	if(is_set(input_register, R_REQ_PEND)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_REQ_PEND)",
 			      text, R_REQ_PEND);
 	}
 	if(is_set(input_register, R_PE_PEND)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_PE_PEND)",
 			      text, R_PE_PEND);
 	}
 	if(is_set(input_register, R_TE_PEND)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_TE_PEND)",
 			      text, R_TE_PEND);
 	}
 	if(is_set(input_register, R_RESP_PEND)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_RESP_PEND)",
 			      text, R_RESP_PEND);
 	}
 	if(is_set(input_register, R_CIB_DONE)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_CIB_DONE)",
 			      text, R_CIB_DONE);
 	}
 	if(is_set(input_register, R_HAVE_CIB)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_HAVE_CIB)",
 			      text, R_HAVE_CIB);
 	}
 	if(is_set(input_register, R_CIB_ASKED)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_CIB_ASKED)",
 			      text, R_CIB_ASKED);
 	}
 	if(is_set(input_register, R_CCM_DATA)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_CCM_DATA)",
 			      text, R_CCM_DATA);
 	}	
 	if(is_set(input_register, R_PEER_DATA)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_PEER_DATA)",
 			      text, R_PEER_DATA);
 	}
 	if(is_set(input_register, R_IN_RECOVERY)) {
 		crm_log_maybe(log_level, "%s %.16llx (R_IN_RECOVERY)",
 			      text, R_IN_RECOVERY);
 	}
 }
 
 void
 fsa_dump_actions(long long action, const char *text)
 {
 	int log_level = LOG_DEBUG_3;
 	
 	if(is_set(action, A_READCONFIG)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text);
 	}
 	if(is_set(action, A_STARTUP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_STARTUP) %s", A_STARTUP, text);
 	}
 	if(is_set(action, A_STARTED)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_STARTED) %s", A_STARTED, text);
 	}
 	if(is_set(action, A_HA_CONNECT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text);
 	}
 	if(is_set(action, A_HA_DISCONNECT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DISCONNECT) %s",
 			  A_HA_DISCONNECT, text);
 	}
 	if(is_set(action, A_LRM_CONNECT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_LRM_CONNECT) %s",
 			  A_LRM_CONNECT, text);
 	}
 	if(is_set(action, A_LRM_EVENT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_LRM_EVENT) %s",
 			  A_LRM_EVENT, text);
 	}
 	if(is_set(action, A_LRM_INVOKE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_LRM_INVOKE) %s",
 			  A_LRM_INVOKE, text);
 	}
 	if(is_set(action, A_LRM_DISCONNECT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_LRM_DISCONNECT) %s",
 			  A_LRM_DISCONNECT, text);
 	}
 	if(is_set(action, A_DC_TIMER_STOP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_TIMER_STOP) %s",
 			  A_DC_TIMER_STOP, text);
 	}
 	if(is_set(action, A_DC_TIMER_START)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_TIMER_START) %s",
 			  A_DC_TIMER_START, text);
 	}
 	if(is_set(action, A_INTEGRATE_TIMER_START)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_INTEGRATE_TIMER_START) %s",
 			  A_INTEGRATE_TIMER_START, text);
 	}
 	if(is_set(action, A_INTEGRATE_TIMER_STOP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_INTEGRATE_TIMER_STOP) %s",
 			  A_INTEGRATE_TIMER_STOP, text);
 	}
 	if(is_set(action, A_FINALIZE_TIMER_START)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_FINALIZE_TIMER_START) %s",
 			  A_FINALIZE_TIMER_START, text);
 	}
 	if(is_set(action, A_FINALIZE_TIMER_STOP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_FINALIZE_TIMER_STOP) %s",
 			  A_FINALIZE_TIMER_STOP, text);
 	}
 	if(is_set(action, A_ELECTION_COUNT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_ELECTION_COUNT) %s",
 			  A_ELECTION_COUNT, text);
 	}
 	if(is_set(action, A_ELECTION_VOTE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_ELECTION_VOTE) %s",
 			  A_ELECTION_VOTE, text);
 	}
 	if(is_set(action, A_ELECTION_CHECK)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_ELECTION_CHECK) %s",
 			  A_ELECTION_CHECK, text);
 	}
 	if(is_set(action, A_CL_JOIN_ANNOUNCE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CL_JOIN_ANNOUNCE) %s",
 			  A_CL_JOIN_ANNOUNCE, text);
 	}
 	if(is_set(action, A_CL_JOIN_REQUEST)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CL_JOIN_REQUEST) %s",
 			  A_CL_JOIN_REQUEST, text);
 	}
 	if(is_set(action, A_CL_JOIN_RESULT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CL_JOIN_RESULT) %s",
 			  A_CL_JOIN_RESULT, text);
 	}
 	if(is_set(action, A_DC_JOIN_OFFER_ALL)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_JOIN_OFFER_ALL) %s",
 			  A_DC_JOIN_OFFER_ALL, text);
 	}
 	if(is_set(action, A_DC_JOIN_OFFER_ONE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_JOIN_OFFER_ONE) %s",
 			  A_DC_JOIN_OFFER_ONE, text);
 	}
 	if(is_set(action, A_DC_JOIN_PROCESS_REQ)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s",
 			  A_DC_JOIN_PROCESS_REQ, text);
 	}
 	if(is_set(action, A_DC_JOIN_PROCESS_ACK)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s",
 			  A_DC_JOIN_PROCESS_ACK, text);
 	}
 	if(is_set(action, A_DC_JOIN_FINALIZE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_JOIN_FINALIZE) %s",
 			  A_DC_JOIN_FINALIZE, text);
 	}
 	if(is_set(action, A_MSG_PROCESS)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_MSG_PROCESS) %s",
 			  A_MSG_PROCESS, text);
 	}
 	if(is_set(action, A_MSG_ROUTE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_MSG_ROUTE) %s",
 			  A_MSG_ROUTE, text);
 	}
 	if(is_set(action, A_RECOVER)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_RECOVER) %s",
 			  A_RECOVER, text);
 	}
 	if(is_set(action, A_DC_RELEASE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_RELEASE) %s",
 			  A_DC_RELEASE, text);
 	}
 	if(is_set(action, A_DC_RELEASED)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_RELEASED) %s",
 			  A_DC_RELEASED, text);
 	}
 	if(is_set(action, A_DC_TAKEOVER)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_DC_TAKEOVER) %s",
 			  A_DC_TAKEOVER, text);
 	}
 	if(is_set(action, A_SHUTDOWN)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text);
 	}
 	if(is_set(action, A_SHUTDOWN_REQ)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_SHUTDOWN_REQ) %s",
 			  A_SHUTDOWN_REQ, text);
 	}
 	if(is_set(action, A_STOP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_STOP  ) %s", A_STOP  , text);
 	}
 	if(is_set(action, A_EXIT_0)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text);
 	}
 	if(is_set(action, A_EXIT_1)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text);
 	}
 	if(is_set(action, A_CCM_CONNECT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CCM_CONNECT) %s",
 			  A_CCM_CONNECT, text);
 	}
 	if(is_set(action, A_CCM_DISCONNECT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CCM_DISCONNECT) %s",
 			  A_CCM_DISCONNECT, text);
 	}
 	if(is_set(action, A_CCM_EVENT)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CCM_EVENT) %s",
 			  A_CCM_EVENT, text);
 	}
 	if(is_set(action, A_CCM_UPDATE_CACHE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CCM_UPDATE_CACHE) %s",
 			  A_CCM_UPDATE_CACHE, text);
 	}
 	if(is_set(action, A_CIB_BUMPGEN)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CIB_BUMPGEN) %s",
 			  A_CIB_BUMPGEN, text);
 	}
 	if(is_set(action, A_CIB_INVOKE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CIB_INVOKE) %s",
 			  A_CIB_INVOKE, text);
 	}
 	if(is_set(action, A_CIB_START)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CIB_START) %s",
 			  A_CIB_START, text);
 	}
 	if(is_set(action, A_CIB_STOP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text);
 	}
 	if(is_set(action, A_TE_INVOKE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text);
 	}
 	if(is_set(action, A_TE_START)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_TE_START) %s",
 			  A_TE_START, text);
 	}
 	if(is_set(action, A_TE_STOP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text);
 	}
 	if(is_set(action, A_TE_CANCEL)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_TE_CANCEL) %s",
 			  A_TE_CANCEL, text);
 	}
 	if(is_set(action, A_PE_INVOKE)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_PE_INVOKE) %s",
 			  A_PE_INVOKE, text);
 	}
 	if(is_set(action, A_PE_START)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_PE_START) %s", A_PE_START, text);
 	}
 	if(is_set(action, A_PE_STOP)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text);
 	}
 	if(is_set(action, A_NODE_BLOCK)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_NODE_BLOCK) %s",
 			  A_NODE_BLOCK, text);
 	}
 	if(is_set(action, A_UPDATE_NODESTATUS)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_UPDATE_NODESTATUS) %s",
 			  A_UPDATE_NODESTATUS, text);
 	}
 	if(is_set(action, A_LOG)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_LOG   ) %s", A_LOG, text);
 	}
 	if(is_set(action, A_ERROR)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_ERROR ) %s", A_ERROR, text);
 	}
 	if(is_set(action, A_WARN)) {
 		crm_log_maybe(log_level, 
 			   "Action %.16llx (A_WARN  ) %s", A_WARN, text);
 	}
 }
 
 
 void
 create_node_entry(const char *uuid, const char *uname, const char *type)
 {
 	
 	/* make sure a node entry exists for the new node
 	 *
 	 * this will add anyone except the first ever node in the cluster
 	 *   since it will also be the DC which doesnt go through the
 	 *   join process (with itself).  We can include a special case
 	 *   later if desired.
 	 */
 	crm_data_t *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE);
 
 	crm_debug_3("Creating node entry for %s", uname);
 	set_uuid(fsa_cluster_conn, tmp1, XML_ATTR_UUID, uname);
 	
 	crm_xml_add(tmp1, XML_ATTR_UNAME, uname);
 	crm_xml_add(tmp1, XML_ATTR_TYPE, type);
 
 	fsa_cib_anon_update(XML_CIB_TAG_NODES, tmp1,
 			    cib_scope_local|cib_quorum_override);
 
 	free_xml(tmp1);
 	
 }
 
 
 
 
 struct crmd_ccm_data_s *
 copy_ccm_data(const struct crmd_ccm_data_s *ccm_input) 
 {
 	const oc_ev_membership_t *oc_in =
 		(const oc_ev_membership_t *)ccm_input->oc;
 	struct crmd_ccm_data_s *ccm_input_copy = NULL;
 
 	crm_malloc0(ccm_input_copy, sizeof(struct crmd_ccm_data_s));
 
 	ccm_input_copy->oc = copy_ccm_oc_data(oc_in);
 	ccm_input_copy->event = ccm_input->event;
 	
 	return ccm_input_copy;
 }
 
 oc_ev_membership_t *
 copy_ccm_oc_data(const oc_ev_membership_t *oc_in) 
 {
 	unsigned lpc = 0;
 	int size = 0;
 	int offset = 0;
 	unsigned num_nodes = 0;
 	oc_ev_membership_t *oc_copy = NULL;
 
 	if(oc_in->m_n_member > 0
 	   && num_nodes < oc_in->m_n_member + oc_in->m_memb_idx) {
 		num_nodes = oc_in->m_n_member + oc_in->m_memb_idx;
 		crm_debug_3("Updated ccm nodes to %d - 1", num_nodes);
 	}
 	if(oc_in->m_n_in > 0
 	   && num_nodes < oc_in->m_n_in + oc_in->m_in_idx) {
 		num_nodes = oc_in->m_n_in + oc_in->m_in_idx;
 		crm_debug_3("Updated ccm nodes to %d - 2", num_nodes);
 	}
 	if(oc_in->m_n_out > 0
 	   && num_nodes < oc_in->m_n_out + oc_in->m_out_idx) {
 		num_nodes = oc_in->m_n_out + oc_in->m_out_idx;
 		crm_debug_3("Updated ccm nodes to %d - 3", num_nodes);
 	}
 
 	/* why 2*??
 	 * ccm code does it like this so i guess its right...
 	 */
 	size = sizeof(oc_ev_membership_t)
 		+ sizeof(int)
 		+ 2*num_nodes*sizeof(oc_node_t);
 
 	crm_debug_3("Copying %d ccm nodes", num_nodes);
 	
 	crm_malloc0(oc_copy, size);
 
 	oc_copy->m_instance = oc_in->m_instance;
 	oc_copy->m_n_member = oc_in->m_n_member;
 	oc_copy->m_memb_idx = oc_in->m_memb_idx;
 	oc_copy->m_n_out    = oc_in->m_n_out;
 	oc_copy->m_out_idx  = oc_in->m_out_idx;
 	oc_copy->m_n_in     = oc_in->m_n_in;
 	oc_copy->m_in_idx   = oc_in->m_in_idx;
 
 	crm_debug_3("instance=%d, nodes=%d (idx=%d), new=%d (idx=%d), lost=%d (idx=%d)",
 		  oc_in->m_instance,
 		  oc_in->m_n_member,
 		  oc_in->m_memb_idx,
 		  oc_in->m_n_in,
 		  oc_in->m_in_idx,
 		  oc_in->m_n_out,
 		  oc_in->m_out_idx);
 
 	offset = oc_in->m_memb_idx;
 	for(lpc = 0; lpc < oc_in->m_n_member; lpc++) {
 		oc_node_t a_node      = oc_in->m_array[lpc+offset];
 		oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
 		crm_debug_3("Copying ccm member node %d", lpc);
 		copy_ccm_node(a_node, a_node_copy);
 		
 	}
 
 	offset = oc_in->m_in_idx;
 	for(lpc = 0; lpc < oc_in->m_n_in; lpc++) {
 		oc_node_t a_node      = oc_in->m_array[lpc+offset];
 		oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
 		crm_debug_3("Copying ccm new node %d", lpc);
 		copy_ccm_node(a_node, a_node_copy);
 		
 	}
 
 	offset = oc_in->m_out_idx;
 	for(lpc = 0; lpc < oc_in->m_n_out; lpc++) {
 		oc_node_t a_node      = oc_in->m_array[lpc+offset];
 		oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
 		crm_debug_3("Copying ccm lost node %d", lpc);
 		copy_ccm_node(a_node, a_node_copy);
 	}
 	
 	return oc_copy;
 }
 
 
 void
 copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy)
 {
 	crm_debug_3("Copying ccm node: id=%d, born=%d, uname=%s",
 		  a_node.node_id, a_node.node_born_on,
 		  a_node.node_uname);
 	
 	a_node_copy->node_id      = a_node.node_id;
 	a_node_copy->node_born_on = a_node.node_born_on;	
 	a_node_copy->node_uname   = NULL;
 	
 	if(a_node.node_uname != NULL) {
 			a_node_copy->node_uname =
 				crm_strdup(a_node.node_uname);
 	} else {
 		crm_err("Node Id %d had a NULL uname!",
 			a_node.node_id);
 	}
 	
 	crm_debug_3("Copied ccm node: id=%d, born=%d, uname=%s",
 		  a_node_copy->node_id, a_node_copy->node_born_on,
 		  a_node_copy->node_uname);
 }
 
 crm_data_t*
 create_node_state(
 	const char *uname, const char *ha_state, const char *ccm_state,
 	const char *crmd_state, const char *join_state, const char *exp_state,
 	gboolean clear_shutdown, const char *src)
 {
 	crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
 
 	crm_debug_2("%s Creating node state entry for %s", src, uname);
 	set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, uname);
 
+	if(ID(node_state) == NULL) {
+		crm_debug("Node %s is not a cluster member", uname);
+		free_xml(node_state);
+		return NULL;
+	}
+	
 	crm_xml_add(node_state, XML_ATTR_UNAME,         uname);
 	crm_xml_add(node_state, XML_CIB_ATTR_HASTATE,   ha_state);
 	crm_xml_add(node_state, XML_CIB_ATTR_INCCM,     ccm_state);
 	crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state);
 	crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, join_state);
 	crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE,  exp_state);
 	crm_xml_add(node_state, XML_ATTR_ORIGIN, src);
 
 	if(clear_shutdown) {
 		crm_xml_add(node_state, XML_CIB_ATTR_SHUTDOWN,  "0");
 #if CRM_DEPRECATED_SINCE_2_0_3
 		crm_xml_add(node_state, "clear_shutdown",  "true");
 #endif
 /* 		crm_xml_add(node_state, */
 /* 			    XML_CIB_ATTR_REPLACE, XML_TAG_TRANSIENT_NODEATTRS); */
 	}
 	
 		
 	
 	crm_log_xml_debug_3(node_state, "created");
 
 	return node_state;
 }
 
 gboolean
 need_transition(enum crmd_fsa_state state)
 {
 	if(state == S_POLICY_ENGINE
 	   || state == S_TRANSITION_ENGINE
 	   || state == S_IDLE) {
 		return TRUE;
 	}
 	return FALSE;
 }
 
 extern GHashTable   *ipc_clients;
 
 void
 process_client_disconnect(crmd_client_t *curr_client) 
 {
 	struct crm_subsystem_s *the_subsystem = NULL;
 
 	CRM_CHECK(curr_client != NULL, return);
 	crm_debug_2("received HUP from %s", curr_client->table_key);
 		
 	if (curr_client->sub_sys == NULL) {
 		crm_debug_2("Client hadn't registered with us yet");
 		
 	} else if (strcasecmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) {
 		the_subsystem = pe_subsystem;
 		
 	} else if (strcasecmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) {
 		the_subsystem = te_subsystem;
 			
 	} else if (strcasecmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){
 		the_subsystem = cib_subsystem;
 	}
 		
 	if(the_subsystem != NULL) {
 		the_subsystem->ipc = NULL;
 		crm_info("Received HUP from %s:[%d]",
 			 the_subsystem->name, the_subsystem->pid);
 		
 	} else {
 		/* else that was a transient client */
 		crm_debug("Received HUP from transient client");
 	}
 	
 	if (curr_client->table_key != NULL) {
 		/*
 		 * Key is destroyed below:
 		 *	curr_client->table_key
 		 * Value is cleaned up by:
 		 *	G_main_del_IPC_Channel
 		 */
 		g_hash_table_remove(ipc_clients, curr_client->table_key);
 	}
 }
 
 void update_dc(HA_Message *msg, gboolean assert_same)
 {
 	const char *dc_version = NULL;
 	const char *welcome_from = NULL;
 
 	if(msg != NULL) {
 		dc_version = cl_get_string(msg, F_CRM_VERSION);
 		welcome_from = cl_get_string(msg, F_CRM_HOST_FROM);
 		
 		CRM_CHECK(dc_version != NULL, return);
 		CRM_CHECK(welcome_from != NULL, return);
 		if(AM_I_DC) {
 			CRM_CHECK(safe_str_eq(welcome_from, fsa_our_uname),
 				  return);
 		}
 		if(assert_same) {
 			CRM_CHECK(fsa_our_dc != NULL, ;);
 			CRM_CHECK(safe_str_eq(fsa_our_dc, welcome_from), ;);
 		}
 		
 	}
 	
 	crm_free(fsa_our_dc);
 	crm_free(fsa_our_dc_version);
 	fsa_our_dc = NULL;
 	fsa_our_dc_version = NULL;
 
 	if(welcome_from != NULL) {
 		fsa_our_dc = crm_strdup(welcome_from);
 	}
 	if(dc_version != NULL) {
 		fsa_our_dc_version = crm_strdup(dc_version);
 	}
 
 	crm_info("Set DC to %s (%s)",
 		 crm_str(fsa_our_dc), crm_str(fsa_our_dc_version));
 }