1    	/*
2    	 * Copyright 2009-2026 the Pacemaker project contributors
3    	 *
4    	 * The version control history for this file may have further details.
5    	 *
6    	 * This source code is licensed under the GNU General Public License version 2
7    	 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8    	 */
9    	
10   	#include <crm_internal.h>
11   	
12   	#include <inttypes.h>                         // uint32_t, PRIu32
13   	#include <stdlib.h>                           // NULL, free, size_t
14   	
15   	#include <corosync/cpg.h>                     // cpg_handle_t, cpg_name
16   	#include <glib.h>                             // gpointer
17   	#include <libxml/tree.h>                      // xmlNode
18   	
19   	#include <crm/cluster.h>                      // pcmk_cluster_connect
20   	#include <crm/common/ipc.h>                   // pcmk_ipc_server
21   	#include <crm/common/results.h>               // pcmk_rc_*
22   	#include <crm/stonith-ng.h>                   // st_opt_*
23   	
24   	#include "pacemaker-fenced.h"
25   	
26   	pcmk_cluster_t *fenced_cluster = NULL;
27   	
28   	static void
29   	handle_cpg_reply(const char *remote_peer, xmlNode *request)
30   	{
31   	    const char *op = pcmk__xe_get(request, PCMK__XA_ST_OP);
32   	
33   	    if (pcmk__str_eq(op, STONITH_OP_QUERY, pcmk__str_none)) {
34   	        process_remote_stonith_query(request);
35   	
36   	    } else if (pcmk__str_any_of(op, STONITH_OP_NOTIFY, STONITH_OP_FENCE,
37   	                                NULL)) {
38   	        fenced_process_fencing_reply(request);
39   	
40   	    } else {
41   	        pcmk__err("Ignoring unknown %s reply from peer %s",
42   	                  pcmk__s(op, "untyped"), remote_peer);
43   	        pcmk__log_xml_warn(request, "UnknownOp");
44   	        return;
45   	    }
46   	
47   	    pcmk__debug("Processed %s reply from peer %s", op, remote_peer);
48   	}
49   	
50   	static void
51   	fenced_peer_message(pcmk__node_status_t *peer, xmlNode *xml)
52   	{
53   	    const char *op = pcmk__xe_get(xml, PCMK__XA_ST_OP);
54   	    int rc = pcmk_rc_ok;
55   	
56   	    if (pcmk__str_eq(op, STONITH_OP_POKE, pcmk__str_none)) {
57   	        return;
58   	    }
59   	
60   	    if (pcmk__xpath_find_one(xml->doc, "//" PCMK__XE_ST_REPLY,
61   	                             PCMK__LOG_NEVER) != NULL) {
62   	        handle_cpg_reply(peer->name, xml);
63   	
64   	    } else {
65   	        pcmk__request_t request = {
66   	            .ipc_client     = NULL,
67   	            .ipc_id         = 0,
68   	            .ipc_flags      = crm_ipc_flags_none,
69   	            .peer           = peer->name,
70   	            .xml            = xml,
71   	            .call_options   = st_opt_none,
72   	            .result         = PCMK__UNKNOWN_RESULT,
73   	        };
74   	
75   	        rc = pcmk__xe_get_flags(xml, PCMK__XA_ST_CALLOPT,
76   	                                (uint32_t *) &request.call_options, st_opt_none);
77   	        if (rc != pcmk_rc_ok) {
78   	            pcmk__warn("Couldn't parse options from request: %s",
79   	                       pcmk_rc_str(rc));
80   	        }
81   	
82   	        request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_ST_OP);
83   	        CRM_CHECK(request.op != NULL, return);
84   	
85   	        if (pcmk__is_set(request.call_options, st_opt_sync_call)) {
86   	            pcmk__set_request_flags(&request, pcmk__request_sync);
87   	        }
88   	
89   	        fenced_handle_request(&request);
90   	    }
91   	}
92   	
93   	/*!
94   	 * \internal
95   	 * \brief Callback for peer status changes
96   	 *
97   	 * \param[in] type  What changed
98   	 * \param[in] node  What peer had the change
99   	 * \param[in] data  Previous value of what changed
100  	 */
101  	static void
102  	fenced_peer_change_cb(enum pcmk__node_update type, pcmk__node_status_t *node,
103  	                      const void *data)
104  	{
105  	    if ((type != pcmk__node_update_processes)
106  	        && !pcmk__is_set(node->flags, pcmk__node_status_remote)) {
107  	        /*
108  	         * This is a hack until we can send to a nodeid and/or we fix node name lookups
109  	         * These messages are ignored in stonith_peer_callback()
110  	         */
111  	        xmlNode *query = pcmk__xe_create(NULL, PCMK__XE_STONITH_COMMAND);
112  	
113  	        pcmk__xe_set(query, PCMK__XA_T, PCMK__VALUE_STONITH_NG);
114  	        pcmk__xe_set(query, PCMK__XA_ST_OP, STONITH_OP_POKE);
115  	
116  	        pcmk__debug("Broadcasting our uname because of node %" PRIu32,
117  	                    node->cluster_layer_id);
118  	        pcmk__cluster_send_message(NULL, pcmk_ipc_fenced, query);
119  	
120  	        pcmk__xml_free(query);
121  	    }
122  	}
123  	
124  	#if SUPPORT_COROSYNC
125  	/*!
126  	 * \internal
127  	 * \brief Callback for when a peer message is received
128  	 *
129  	 * \param[in]     handle     The cluster connection
130  	 * \param[in]     group_name The group that \p nodeid is a member of
131  	 * \param[in]     nodeid     Peer node that sent \p msg
132  	 * \param[in]     pid        Process that sent \p msg
133  	 * \param[in,out] msg        Received message
134  	 * \param[in]     msg_len    Length of \p msg
135  	 */
136  	static void
137  	fenced_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name,
138  	                    uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
139  	{
140  	    xmlNode *xml = NULL;
141  	    const char *from = NULL;
142  	    char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from);
143  	
144  	    if (data == NULL) {
145  	        return;
146  	    }
147  	
148  	    xml = pcmk__xml_parse(data);
149  	    if (xml == NULL) {
150  	        pcmk__err("Bad message received from %s[%" PRIu32 "]: '%.120s'",
151  	                  from, nodeid, data);
152  	    } else {
153  	        pcmk__xe_set(xml, PCMK__XA_SRC, from);
154  	        fenced_peer_message(pcmk__get_node(nodeid, from, NULL,
155  	                                           pcmk__node_search_cluster_member),
156  	                            xml);
157  	    }
158  	
159  	    pcmk__xml_free(xml);
160  	    free(data);
161  	}
162  	
163  	/*!
164  	 * \internal
165  	 * \brief Callback for when the cluster object is destroyed
166  	 *
167  	 * \param[in] unused Unused
168  	 */
169  	static void
170  	fenced_cpg_destroy(gpointer unused)
171  	{
172  	    pcmk__crit("Lost connection to cluster layer, shutting down");
173  	    stonith_shutdown(0);
174  	}
175  	#endif // SUPPORT_COROSYNC
176  	
177  	int
178  	fenced_cluster_connect(void)
179  	{
180  	    int rc = pcmk_rc_ok;
181  	
182  	    fenced_cluster = pcmk_cluster_new();
183  	
184  	#if SUPPORT_COROSYNC
185  	    if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) {
186  	        pcmk_cluster_set_destroy_fn(fenced_cluster, fenced_cpg_destroy);
187  	        pcmk_cpg_set_deliver_fn(fenced_cluster, fenced_cpg_dispatch);
188  	        pcmk_cpg_set_confchg_fn(fenced_cluster, pcmk__cpg_confchg_cb);
189  	    }
190  	#endif // SUPPORT_COROSYNC
191  	
192  	    pcmk__cluster_set_status_callback(&fenced_peer_change_cb);
193  	
194  	    rc = pcmk_cluster_connect(fenced_cluster);
195  	    if (rc != pcmk_rc_ok) {
196  	        pcmk__err("Cluster connection failed");
197  	    }
198  	
199  	    return rc;
200  	}
201  	
202  	void
203  	fenced_cluster_disconnect(void)
204  	{
(1) Event path: Condition "fenced_cluster == NULL", taking false branch.
205  	    if (fenced_cluster == NULL) {
206  	        return;
207  	    }
208  	
209  	    pcmk_cluster_disconnect(fenced_cluster);
CID (unavailable; MK=cf8bc0ac10c1620539d042a481cb742d) (#1 of 1): Inconsistent C union access (INCONSISTENT_UNION_ACCESS):
(2) Event assign_union_field: The union field "in" of "_pp" is written.
(3) Event inconsistent_union_field_access: In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in".
210  	    g_clear_pointer(&fenced_cluster, pcmk_cluster_free);
211  	}
212