| /* |
| * 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include <crm_internal.h> |
| |
| #include <sys/param.h> |
| |
| #include <crm/crm.h> |
| #include <crm/cluster/internal.h> |
| #include <crm/common/xml.h> |
| |
| #include <crmd.h> |
| #include <crmd_fsa.h> |
| #include <fsa_proto.h> |
| #include <crmd_messages.h> |
| #include <crmd_callbacks.h> |
| #include <crmd_lrm.h> |
| #include <tengine.h> |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| extern void post_cache_update(int seq); |
| extern void crmd_ha_connection_destroy(gpointer user_data); |
| |
| /* A_HA_CONNECT */ |
| #if SUPPORT_COROSYNC |
| |
| static void |
| crmd_cs_dispatch(cpg_handle_t handle, |
| const struct cpg_name *groupName, |
| uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) |
| { |
| int seq = 0; |
| xmlNode *xml = NULL; |
| const char *seq_s = NULL; |
| crm_node_t *peer = NULL; |
| enum crm_proc_flag flag = crm_proc_cpg; |
| |
| uint32_t kind = 0; |
| const char *from = NULL; |
| char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from); |
| |
| if(data == NULL) { |
| return; |
| } |
| xml = string2xml(data); |
| if (xml == NULL) { |
| crm_err("Could not parse message content (%d): %.100s", kind, data); |
| free(data); |
| return; |
| } |
| |
| switch (kind) { |
| case crm_class_members: |
| seq_s = crm_element_value(xml, "id"); |
| seq = crm_int_helper(seq_s, NULL); |
| set_bit(fsa_input_register, R_PEER_DATA); |
| post_cache_update(seq); |
| |
| /* fall through */ |
| case crm_class_quorum: |
| crm_update_quorum(crm_have_quorum, FALSE); |
| if (AM_I_DC) { |
| const char *votes = crm_element_value(xml, "expected"); |
| |
| if (votes == NULL || check_number(votes) == FALSE) { |
| crm_log_xml_err(xml, "Invalid quorum/membership update"); |
| |
| } else { |
| int rc = update_attr_delegate(fsa_cib_conn, |
| cib_quorum_override | cib_scope_local | |
| cib_inhibit_notify, |
| XML_CIB_TAG_CRMCONFIG, NULL, NULL, NULL, NULL, |
| XML_ATTR_EXPECTED_VOTES, votes, FALSE, NULL, NULL); |
| |
| crm_info("Setting expected votes to %s", votes); |
| if (pcmk_ok > rc) { |
| crm_err("Quorum update failed: %s", pcmk_strerror(rc)); |
| } |
| } |
| } |
| break; |
| |
| case crm_class_cluster: |
| crm_xml_add(xml, F_ORIG, from); |
| /* crm_xml_add_int(xml, F_SEQ, wrapper->id); Fake? */ |
| |
| if (is_heartbeat_cluster()) { |
| flag = crm_proc_heartbeat; |
| |
| } else if (is_classic_ais_cluster()) { |
| flag = crm_proc_plugin; |
| } |
| |
| peer = crm_get_peer(0, from); |
| if (is_not_set(peer->processes, flag)) { |
| /* If we can still talk to our peer process on that node, |
| * then its also part of the corosync membership |
| */ |
| crm_warn("Receiving messages from a node we think is dead: %s[%d]", peer->uname, |
| peer->id); |
| crm_update_peer_proc(__FUNCTION__, peer, flag, ONLINESTATUS); |
| } |
| crmd_ha_msg_filter(xml); |
| break; |
| |
| case crm_class_rmpeer: |
| /* Ignore */ |
| break; |
| |
| case crm_class_notify: |
| case crm_class_nodeid: |
| crm_err("Unexpected message class (%d): %.100s", kind, data); |
| break; |
| |
| default: |
| crm_err("Invalid message class (%d): %.100s", kind, data); |
| } |
| |
| free(data); |
| free_xml(xml); |
| } |
| |
| static gboolean |
| crmd_cman_dispatch(unsigned long long seq, gboolean quorate) |
| { |
| crm_update_quorum(quorate, FALSE); |
| post_cache_update(seq); |
| return TRUE; |
| } |
| |
| // OpenBSD doesn't have ENOLINK |
| #ifdef ENOLINK |
| #define CRM_EX_NOLINK ENOLINK |
| #else |
| #define CRM_EX_NOLINK ENOTCONN |
| #endif |
| |
| static void |
| crmd_quorum_destroy(gpointer user_data) |
| { |
| if (is_not_set(fsa_input_register, R_HA_DISCONNECTED)) { |
| crm_err("connection terminated"); |
| crmd_exit(CRM_EX_NOLINK); |
| |
| } else { |
| crm_info("connection closed"); |
| } |
| } |
| |
| static void |
| crmd_cs_destroy(gpointer user_data) |
| { |
| if (is_not_set(fsa_input_register, R_HA_DISCONNECTED)) { |
| crm_err("connection terminated"); |
| crmd_exit(CRM_EX_NOLINK); |
| |
| } else { |
| crm_info("connection closed"); |
| } |
| } |
| |
| # if SUPPORT_CMAN |
| static void |
| crmd_cman_destroy(gpointer user_data) |
| { |
| if (is_not_set(fsa_input_register, R_HA_DISCONNECTED)) { |
| crm_err("connection terminated"); |
| crmd_exit(CRM_EX_NOLINK); |
| |
| } else { |
| crm_info("connection closed"); |
| } |
| } |
| # endif |
| |
| extern gboolean crm_connect_corosync(crm_cluster_t * cluster); |
| |
| gboolean |
| crm_connect_corosync(crm_cluster_t * cluster) |
| { |
| gboolean rc = FALSE; |
| |
| if (is_openais_cluster()) { |
| crm_set_status_callback(&peer_update_callback); |
| cluster->cpg.cpg_deliver_fn = crmd_cs_dispatch; |
| cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership; |
| cluster->destroy = crmd_cs_destroy; |
| |
| rc = crm_cluster_connect(cluster); |
| } |
| |
| if (rc && is_corosync_cluster()) { |
| cluster_connect_quorum(crmd_cman_dispatch, crmd_quorum_destroy); |
| } |
| # if SUPPORT_CMAN |
| if (rc && is_cman_cluster()) { |
| init_cman_connection(crmd_cman_dispatch, crmd_cman_destroy); |
| set_bit(fsa_input_register, R_MEMBERSHIP); |
| } |
| # endif |
| return rc; |
| } |
| |
| #endif |