pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
messages.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #include <stdio.h>
13 #include <time.h> // time()
14 #include <sys/types.h>
15 
16 #include <glib.h>
17 #include <libxml/tree.h>
18 
19 #include <crm/common/xml.h>
21 
57 xmlNode *
58 pcmk__new_message_as(const char *origin, enum pcmk_ipc_server server,
59  const char *reply_to, const char *sender_system,
60  const char *recipient_node, const char *recipient_system,
61  const char *task, xmlNode *data)
62 {
63  static unsigned int message_counter = 0U;
64 
65  xmlNode *message = NULL;
66  char *message_id = NULL;
67  const char *subtype = PCMK__VALUE_RESPONSE;
68 
69  CRM_CHECK(!pcmk__str_empty(origin)
70  && !pcmk__str_empty(sender_system)
71  && !pcmk__str_empty(task),
72  return NULL);
73 
74  if (reply_to == NULL) {
75  subtype = PCMK__VALUE_REQUEST;
76  message_id = crm_strdup_printf("%s-%s-%llu-%u", task, sender_system,
77  (unsigned long long) time(NULL),
78  message_counter++);
79  reply_to = message_id;
80  }
81 
82  message = pcmk__xe_create(NULL, PCMK__XE_MESSAGE);
83  pcmk__xe_set_props(message,
84  PCMK_XA_ORIGIN, origin,
86  PCMK__XA_SUBT, subtype,
88  PCMK_XA_REFERENCE, reply_to,
89  PCMK__XA_CRM_SYS_FROM, sender_system,
90  PCMK__XA_CRM_HOST_TO, recipient_node,
91  PCMK__XA_CRM_SYS_TO, recipient_system,
92  PCMK__XA_CRM_TASK, task,
93  NULL);
94  if (data != NULL) {
95  xmlNode *wrapper = pcmk__xe_create(message, PCMK__XE_CRM_XML);
96 
97  pcmk__xml_copy(wrapper, data);
98  }
99  free(message_id);
100  return message;
101 }
102 
122 xmlNode *
123 pcmk__new_reply_as(const char *origin, const xmlNode *original_request,
124  xmlNode *data)
125 {
126  const char *message_type = crm_element_value(original_request, PCMK__XA_T);
127  const char *host_from = crm_element_value(original_request, PCMK__XA_SRC);
128  const char *sys_from = crm_element_value(original_request,
130  const char *sys_to = crm_element_value(original_request,
132  const char *type = crm_element_value(original_request, PCMK__XA_SUBT);
133  const char *operation = crm_element_value(original_request,
135  const char *crm_msg_reference = crm_element_value(original_request,
137  enum pcmk_ipc_server server = pcmk__parse_server(message_type);
138 
139  if (server == pcmk_ipc_unknown) {
140  /* @COMPAT Not all requests currently specify a message type, so use a
141  * default that preserves past behavior.
142  *
143  * @TODO Ensure all requests specify a message type, drop this check
144  * after we no longer support rolling upgrades or Pacemaker Remote
145  * connections involving versions before that.
146  */
147  server = pcmk_ipc_controld;
148  }
149 
150  if (type == NULL) {
151  crm_warn("Cannot reply to invalid message: No message type specified");
152  return NULL;
153  }
154 
155  if (strcmp(type, PCMK__VALUE_REQUEST) != 0) {
156  /* Replies should only be generated for request messages, but it's possible
157  * we expect replies to other messages right now so this can't be enforced.
158  */
159  crm_trace("Creating a reply for a non-request original message");
160  }
161 
162  // Since this is a reply, we reverse the sender and recipient info
163  return pcmk__new_message_as(origin, server, crm_msg_reference, sys_to,
164  host_from, sys_from, operation, data);
165 }
166 
180 GHashTable *
182 {
183  GHashTable *commands = g_hash_table_new(g_str_hash, g_str_equal);
184 
185  if (handlers != NULL) {
186  int i;
187 
188  for (i = 0; handlers[i].command != NULL; ++i) {
189  g_hash_table_insert(commands, (gpointer) handlers[i].command,
190  handlers[i].handler);
191  }
192  if (handlers[i].handler != NULL) {
193  // g_str_hash() can't handle NULL, so use empty string for default
194  g_hash_table_insert(commands, (gpointer) "", handlers[i].handler);
195  }
196  }
197  return commands;
198 }
199 
209 xmlNode *
210 pcmk__process_request(pcmk__request_t *request, GHashTable *handlers)
211 {
212  xmlNode *(*handler)(pcmk__request_t *request) = NULL;
213 
214  CRM_CHECK((request != NULL) && (request->op != NULL) && (handlers != NULL),
215  return NULL);
216 
217  if (pcmk_is_set(request->flags, pcmk__request_sync)
218  && (request->ipc_client != NULL)) {
219  CRM_CHECK(request->ipc_client->request_id == request->ipc_id,
220  return NULL);
221  }
222 
223  handler = g_hash_table_lookup(handlers, request->op);
224  if (handler == NULL) {
225  handler = g_hash_table_lookup(handlers, ""); // Default handler
226  if (handler == NULL) {
227  crm_info("Ignoring %s request from %s %s with no handler",
228  request->op, pcmk__request_origin_type(request),
229  pcmk__request_origin(request));
230  return NULL;
231  }
232  }
233 
234  return (*handler)(request);
235 }
236 
243 void
245 {
246  free(request->op);
247  request->op = NULL;
248 
249  pcmk__reset_result(&(request->result));
250 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
xmlNode * pcmk__new_message_as(const char *origin, enum pcmk_ipc_server server, const char *reply_to, const char *sender_system, const char *recipient_node, const char *recipient_system, const char *task, xmlNode *data)
Definition: messages.c:58
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
#define PCMK__VALUE_RESPONSE
char data[0]
Definition: cpg.c:58
enum pcmk_ipc_server type
Definition: cpg.c:51
GHashTable * pcmk__register_handlers(const pcmk__server_command_t handlers[])
Definition: messages.c:181
#define CRM_FEATURE_SET
Definition: crm.h:66
#define PCMK_XA_REFERENCE
Definition: xml_names.h:372
pcmk__client_t * ipc_client
const char * pcmk__server_message_type(enum pcmk_ipc_server server)
Definition: servers.c:162
#define PCMK__XA_SUBT
void pcmk__reset_request(pcmk__request_t *request)
Definition: messages.c:244
#define PCMK__XA_CRM_HOST_TO
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
#define PCMK__XA_CRM_SYS_TO
#define PCMK_XA_ORIGIN
Definition: xml_names.h:351
#define PCMK__XA_CRM_TASK
#define PCMK__XE_MESSAGE
pcmk__action_result_t result
#define crm_warn(fmt, args...)
Definition: logging.h:362
pcmk_ipc_server
Available IPC interfaces.
Definition: ipc.h:48
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define crm_trace(fmt, args...)
Definition: logging.h:372
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
Wrappers for and extensions to libxml2.
enum pcmk_ipc_server pcmk__parse_server(const char *text)
Definition: servers.c:178
#define PCMK__XA_CRM_SYS_FROM
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml_element.c:970
#define PCMK__XE_CRM_XML
Controller.
Definition: ipc.h:52
Unknown or invalid.
Definition: ipc.h:49
xmlNode * pcmk__new_reply_as(const char *origin, const xmlNode *original_request, xmlNode *data)
Definition: messages.c:123
#define PCMK__XA_T
xmlNode * pcmk__process_request(pcmk__request_t *request, GHashTable *handlers)
Definition: messages.c:210
void pcmk__reset_result(pcmk__action_result_t *result)
Definition: results.c:1163
#define PCMK__VALUE_REQUEST
#define crm_info(fmt, args...)
Definition: logging.h:367
#define PCMK__XA_SRC
#define PCMK_XA_VERSION
Definition: xml_names.h:444
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1