root/lib/common/messages.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. create_request_adv
  2. create_reply_adv
  3. get_message_xml
  4. add_message_xml
  5. pcmk__message_name
  6. pcmk__register_handlers
  7. pcmk__process_request

   1 /*
   2  * Copyright 2004-2022 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 <sys/types.h>
  14 
  15 #include <glib.h>
  16 #include <libxml/tree.h>
  17 
  18 #include <crm/msg_xml.h>
  19 #include <crm/common/xml_internal.h>
  20 
  21 /*!
  22  * \brief Create a Pacemaker request (for IPC or cluster layer)
  23  *
  24  * \param[in] task          What to set as the request's task
  25  * \param[in] msg_data      What to add as the request's data contents
  26  * \param[in] host_to       What to set as the request's destination host
  27  * \param[in] sys_to        What to set as the request's destination system
  28  * \param[in] sys_from      If not NULL, set as request's origin system
  29  * \param[in] uuid_from     If not NULL, use in request's origin system
  30  * \param[in] origin        Name of function that called this one
  31  *
  32  * \return XML of new request
  33  *
  34  * \note One of sys_from or uuid_from must be non-NULL
  35  * \note This function should not be called directly, but via the
  36  *       create_request() wrapper.
  37  * \note The caller is responsible for freeing the result using free_xml().
  38  */
  39 xmlNode *
  40 create_request_adv(const char *task, xmlNode * msg_data,
     /* [previous][next][first][last][top][bottom][index][help] */
  41                    const char *host_to, const char *sys_to,
  42                    const char *sys_from, const char *uuid_from,
  43                    const char *origin)
  44 {
  45     static uint ref_counter = 0;
  46 
  47     char *true_from = NULL;
  48     xmlNode *request = NULL;
  49     char *reference = crm_strdup_printf("%s-%s-%lld-%u",
  50                                         (task? task : "_empty_"),
  51                                         (sys_from? sys_from : "_empty_"),
  52                                         (long long) time(NULL), ref_counter++);
  53 
  54     if (uuid_from != NULL) {
  55         true_from = crm_strdup_printf("%s_%s", uuid_from,
  56                                       (sys_from? sys_from : "none"));
  57     } else if (sys_from != NULL) {
  58         true_from = strdup(sys_from);
  59     } else {
  60         crm_err("Cannot create IPC request: No originating system specified");
  61     }
  62 
  63     // host_from will get set for us if necessary by the controller when routed
  64     request = create_xml_node(NULL, __func__);
  65     crm_xml_add(request, F_CRM_ORIGIN, origin);
  66     crm_xml_add(request, F_TYPE, T_CRM);
  67     crm_xml_add(request, F_CRM_VERSION, CRM_FEATURE_SET);
  68     crm_xml_add(request, F_CRM_MSG_TYPE, XML_ATTR_REQUEST);
  69     crm_xml_add(request, F_CRM_REFERENCE, reference);
  70     crm_xml_add(request, F_CRM_TASK, task);
  71     crm_xml_add(request, F_CRM_SYS_TO, sys_to);
  72     crm_xml_add(request, F_CRM_SYS_FROM, true_from);
  73 
  74     /* HOSTTO will be ignored if it is to the DC anyway. */
  75     if (host_to != NULL && strlen(host_to) > 0) {
  76         crm_xml_add(request, F_CRM_HOST_TO, host_to);
  77     }
  78 
  79     if (msg_data != NULL) {
  80         add_message_xml(request, F_CRM_DATA, msg_data);
  81     }
  82     free(reference);
  83     free(true_from);
  84 
  85     return request;
  86 }
  87 
  88 /*!
  89  * \brief Create a Pacemaker reply (for IPC or cluster layer)
  90  *
  91  * \param[in] original_request   XML of request this is a reply to
  92  * \param[in] xml_response_data  XML to copy as data section of reply
  93  * \param[in] origin             Name of function that called this one
  94  *
  95  * \return XML of new reply
  96  *
  97  * \note This function should not be called directly, but via the
  98  *       create_reply() wrapper.
  99  * \note The caller is responsible for freeing the result using free_xml().
 100  */
 101 xmlNode *
 102 create_reply_adv(xmlNode *original_request, xmlNode *xml_response_data,
     /* [previous][next][first][last][top][bottom][index][help] */
 103                  const char *origin)
 104 {
 105     xmlNode *reply = NULL;
 106 
 107     const char *host_from = crm_element_value(original_request, F_CRM_HOST_FROM);
 108     const char *sys_from = crm_element_value(original_request, F_CRM_SYS_FROM);
 109     const char *sys_to = crm_element_value(original_request, F_CRM_SYS_TO);
 110     const char *type = crm_element_value(original_request, F_CRM_MSG_TYPE);
 111     const char *operation = crm_element_value(original_request, F_CRM_TASK);
 112     const char *crm_msg_reference = crm_element_value(original_request, F_CRM_REFERENCE);
 113 
 114     if (type == NULL) {
 115         crm_err("Cannot create new_message, no message type in original message");
 116         CRM_ASSERT(type != NULL);
 117         return NULL;
 118 #if 0
 119     } else if (strcasecmp(XML_ATTR_REQUEST, type) != 0) {
 120         crm_err("Cannot create new_message, original message was not a request");
 121         return NULL;
 122 #endif
 123     }
 124     reply = create_xml_node(NULL, __func__);
 125     if (reply == NULL) {
 126         crm_err("Cannot create new_message, malloc failed");
 127         return NULL;
 128     }
 129 
 130     crm_xml_add(reply, F_CRM_ORIGIN, origin);
 131     crm_xml_add(reply, F_TYPE, T_CRM);
 132     crm_xml_add(reply, F_CRM_VERSION, CRM_FEATURE_SET);
 133     crm_xml_add(reply, F_CRM_MSG_TYPE, XML_ATTR_RESPONSE);
 134     crm_xml_add(reply, F_CRM_REFERENCE, crm_msg_reference);
 135     crm_xml_add(reply, F_CRM_TASK, operation);
 136 
 137     /* since this is a reply, we reverse the from and to */
 138     crm_xml_add(reply, F_CRM_SYS_TO, sys_from);
 139     crm_xml_add(reply, F_CRM_SYS_FROM, sys_to);
 140 
 141     /* HOSTTO will be ignored if it is to the DC anyway. */
 142     if (host_from != NULL && strlen(host_from) > 0) {
 143         crm_xml_add(reply, F_CRM_HOST_TO, host_from);
 144     }
 145 
 146     if (xml_response_data != NULL) {
 147         add_message_xml(reply, F_CRM_DATA, xml_response_data);
 148     }
 149 
 150     return reply;
 151 }
 152 
 153 xmlNode *
 154 get_message_xml(xmlNode *msg, const char *field)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156     xmlNode *tmp = first_named_child(msg, field);
 157 
 158     return pcmk__xml_first_child(tmp);
 159 }
 160 
 161 gboolean
 162 add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164     xmlNode *holder = create_xml_node(msg, field);
 165 
 166     add_node_copy(holder, xml);
 167     return TRUE;
 168 }
 169 
 170 /*!
 171  * \brief Get name to be used as identifier for cluster messages
 172  *
 173  * \param[in] name  Actual system name to check
 174  *
 175  * \return Non-NULL cluster message identifier corresponding to name
 176  *
 177  * \note The Pacemaker daemons were renamed in version 2.0.0, but the old names
 178  *       must continue to be used as the identifier for cluster messages, so
 179  *       that mixed-version clusters are possible during a rolling upgrade.
 180  */
 181 const char *
 182 pcmk__message_name(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184     if (name == NULL) {
 185         return "unknown";
 186 
 187     } else if (!strcmp(name, "pacemaker-attrd")) {
 188         return "attrd";
 189 
 190     } else if (!strcmp(name, "pacemaker-based")) {
 191         return CRM_SYSTEM_CIB;
 192 
 193     } else if (!strcmp(name, "pacemaker-controld")) {
 194         return CRM_SYSTEM_CRMD;
 195 
 196     } else if (!strcmp(name, "pacemaker-execd")) {
 197         return CRM_SYSTEM_LRMD;
 198 
 199     } else if (!strcmp(name, "pacemaker-fenced")) {
 200         return "stonith-ng";
 201 
 202     } else if (!strcmp(name, "pacemaker-schedulerd")) {
 203         return CRM_SYSTEM_PENGINE;
 204 
 205     } else {
 206         return name;
 207     }
 208 }
 209 
 210 /*!
 211  * \internal
 212  * \brief Register handlers for server commands
 213  *
 214  * \param[in] handlers  Array of handler functions for supported server commands
 215  *                      (the final entry must have a NULL command name, and if
 216  *                      it has a handler it will be used as the default handler
 217  *                      for unrecognized commands)
 218  *
 219  * \return Newly created hash table with commands and handlers
 220  * \note The caller is responsible for freeing the return value with
 221  *       g_hash_table_destroy().
 222  */
 223 GHashTable *
 224 pcmk__register_handlers(pcmk__server_command_t *handlers)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226     GHashTable *commands = g_hash_table_new(g_str_hash, g_str_equal);
 227 
 228     if (handlers != NULL) {
 229         int i;
 230 
 231         for (i = 0; handlers[i].command != NULL; ++i) {
 232             g_hash_table_insert(commands, (gpointer) handlers[i].command,
 233                                 handlers[i].handler);
 234         }
 235         if (handlers[i].handler != NULL) {
 236             // g_str_hash() can't handle NULL, so use empty string for default
 237             g_hash_table_insert(commands, (gpointer) "", handlers[i].handler);
 238         }
 239     }
 240     return commands;
 241 }
 242 
 243 /*!
 244  * \internal
 245  * \brief Process an incoming request
 246  *
 247  * \param[in] request   Request to process
 248  * \param[in] handlers  Command table created by pcmk__register_handlers()
 249  *
 250  * \return XML to send as reply (or NULL if no reply is needed)
 251  */
 252 xmlNode *
 253 pcmk__process_request(pcmk__request_t *request, GHashTable *handlers)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255     xmlNode *(*handler)(pcmk__request_t *request) = NULL;
 256 
 257     CRM_CHECK((request != NULL) && (request->op != NULL) && (handlers != NULL),
 258               return NULL);
 259 
 260     if (pcmk_is_set(request->flags, pcmk__request_sync)
 261         && (request->ipc_client != NULL)) {
 262         CRM_CHECK(request->ipc_client->request_id == request->ipc_id,
 263                   return NULL);
 264     }
 265 
 266     handler = g_hash_table_lookup(handlers, request->op);
 267     if (handler == NULL) {
 268         handler = g_hash_table_lookup(handlers, ""); // Default handler
 269         if (handler == NULL) {
 270             crm_info("Ignoring %s request from %s %s with no handler",
 271                      request->op, pcmk__request_origin_type(request),
 272                      pcmk__request_origin(request));
 273             return NULL;
 274         }
 275     }
 276 
 277     return (*handler)(request);
 278 }

/* [previous][next][first][last][top][bottom][index][help] */