LCOV - code coverage report
Current view: top level - common - messages.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 99 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 6 0.0 %

          Line data    Source code
       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 <sys/types.h>
      14             : 
      15             : #include <glib.h>
      16             : #include <libxml/tree.h>
      17             : 
      18             : #include <crm/common/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           0 : create_request_adv(const char *task, xmlNode *msg_data,
      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           0 :     char *true_from = NULL;
      48           0 :     xmlNode *request = NULL;
      49           0 :     char *reference = crm_strdup_printf("%s-%s-%lld-%u",
      50             :                                         (task? task : "_empty_"),
      51             :                                         (sys_from? sys_from : "_empty_"),
      52           0 :                                         (long long) time(NULL), ref_counter++);
      53             : 
      54           0 :     if (uuid_from != NULL) {
      55           0 :         true_from = crm_strdup_printf("%s_%s", uuid_from,
      56             :                                       (sys_from? sys_from : "none"));
      57           0 :     } else if (sys_from != NULL) {
      58           0 :         true_from = strdup(sys_from);
      59             :     } else {
      60           0 :         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           0 :     request = pcmk__xe_create(NULL, __func__);
      65           0 :     crm_xml_add(request, PCMK_XA_ORIGIN, origin);
      66           0 :     crm_xml_add(request, PCMK__XA_T, PCMK__VALUE_CRMD);
      67           0 :     crm_xml_add(request, PCMK_XA_VERSION, CRM_FEATURE_SET);
      68           0 :     crm_xml_add(request, PCMK__XA_SUBT, PCMK__VALUE_REQUEST);
      69           0 :     crm_xml_add(request, PCMK_XA_REFERENCE, reference);
      70           0 :     crm_xml_add(request, PCMK__XA_CRM_TASK, task);
      71           0 :     crm_xml_add(request, PCMK__XA_CRM_SYS_TO, sys_to);
      72           0 :     crm_xml_add(request, PCMK__XA_CRM_SYS_FROM, true_from);
      73             : 
      74             :     /* HOSTTO will be ignored if it is to the DC anyway. */
      75           0 :     if (host_to != NULL && strlen(host_to) > 0) {
      76           0 :         crm_xml_add(request, PCMK__XA_CRM_HOST_TO, host_to);
      77             :     }
      78             : 
      79           0 :     if (msg_data != NULL) {
      80           0 :         xmlNode *wrapper = pcmk__xe_create(request, PCMK__XE_CRM_XML);
      81             : 
      82           0 :         pcmk__xml_copy(wrapper, msg_data);
      83             :     }
      84           0 :     free(reference);
      85           0 :     free(true_from);
      86             : 
      87           0 :     return request;
      88             : }
      89             : 
      90             : /*!
      91             :  * \brief Create a Pacemaker reply (for IPC or cluster layer)
      92             :  *
      93             :  * \param[in] original_request   XML of request this is a reply to
      94             :  * \param[in] xml_response_data  XML to copy as data section of reply
      95             :  * \param[in] origin             Name of function that called this one
      96             :  *
      97             :  * \return XML of new reply
      98             :  *
      99             :  * \note This function should not be called directly, but via the
     100             :  *       create_reply() wrapper.
     101             :  * \note The caller is responsible for freeing the result using free_xml().
     102             :  */
     103             : xmlNode *
     104           0 : create_reply_adv(const xmlNode *original_request, xmlNode *xml_response_data,
     105             :                  const char *origin)
     106             : {
     107           0 :     xmlNode *reply = NULL;
     108             : 
     109           0 :     const char *host_from = crm_element_value(original_request, PCMK__XA_SRC);
     110           0 :     const char *sys_from = crm_element_value(original_request,
     111             :                                              PCMK__XA_CRM_SYS_FROM);
     112           0 :     const char *sys_to = crm_element_value(original_request,
     113             :                                            PCMK__XA_CRM_SYS_TO);
     114           0 :     const char *type = crm_element_value(original_request, PCMK__XA_SUBT);
     115           0 :     const char *operation = crm_element_value(original_request,
     116             :                                               PCMK__XA_CRM_TASK);
     117           0 :     const char *crm_msg_reference = crm_element_value(original_request,
     118             :                                                       PCMK_XA_REFERENCE);
     119             : 
     120           0 :     if (type == NULL) {
     121           0 :         crm_err("Cannot create new_message, no message type in original message");
     122           0 :         CRM_ASSERT(type != NULL);
     123           0 :         return NULL;
     124             :     }
     125             : 
     126           0 :     if (strcmp(type, PCMK__VALUE_REQUEST) != 0) {
     127             :         /* Replies should only be generated for request messages, but it's possible
     128             :          * we expect replies to other messages right now so this can't be enforced.
     129             :          */
     130           0 :         crm_trace("Creating a reply for a non-request original message");
     131             :     }
     132             : 
     133           0 :     reply = pcmk__xe_create(NULL, __func__);
     134           0 :     crm_xml_add(reply, PCMK_XA_ORIGIN, origin);
     135           0 :     crm_xml_add(reply, PCMK__XA_T, PCMK__VALUE_CRMD);
     136           0 :     crm_xml_add(reply, PCMK_XA_VERSION, CRM_FEATURE_SET);
     137           0 :     crm_xml_add(reply, PCMK__XA_SUBT, PCMK__VALUE_RESPONSE);
     138           0 :     crm_xml_add(reply, PCMK_XA_REFERENCE, crm_msg_reference);
     139           0 :     crm_xml_add(reply, PCMK__XA_CRM_TASK, operation);
     140             : 
     141             :     /* since this is a reply, we reverse the from and to */
     142           0 :     crm_xml_add(reply, PCMK__XA_CRM_SYS_TO, sys_from);
     143           0 :     crm_xml_add(reply, PCMK__XA_CRM_SYS_FROM, sys_to);
     144             : 
     145             :     /* HOSTTO will be ignored if it is to the DC anyway. */
     146           0 :     if (host_from != NULL && strlen(host_from) > 0) {
     147           0 :         crm_xml_add(reply, PCMK__XA_CRM_HOST_TO, host_from);
     148             :     }
     149             : 
     150           0 :     if (xml_response_data != NULL) {
     151           0 :         xmlNode *wrapper = pcmk__xe_create(reply, PCMK__XE_CRM_XML);
     152             : 
     153           0 :         pcmk__xml_copy(wrapper, xml_response_data);
     154             :     }
     155             : 
     156           0 :     return reply;
     157             : }
     158             : 
     159             : /*!
     160             :  * \brief Get name to be used as identifier for cluster messages
     161             :  *
     162             :  * \param[in] name  Actual system name to check
     163             :  *
     164             :  * \return Non-NULL cluster message identifier corresponding to name
     165             :  *
     166             :  * \note The Pacemaker daemons were renamed in version 2.0.0, but the old names
     167             :  *       must continue to be used as the identifier for cluster messages, so
     168             :  *       that mixed-version clusters are possible during a rolling upgrade.
     169             :  */
     170             : const char *
     171           0 : pcmk__message_name(const char *name)
     172             : {
     173           0 :     if (name == NULL) {
     174           0 :         return "unknown";
     175             : 
     176           0 :     } else if (!strcmp(name, "pacemaker-attrd")) {
     177           0 :         return "attrd";
     178             : 
     179           0 :     } else if (!strcmp(name, "pacemaker-based")) {
     180           0 :         return CRM_SYSTEM_CIB;
     181             : 
     182           0 :     } else if (!strcmp(name, "pacemaker-controld")) {
     183           0 :         return CRM_SYSTEM_CRMD;
     184             : 
     185           0 :     } else if (!strcmp(name, "pacemaker-execd")) {
     186           0 :         return CRM_SYSTEM_LRMD;
     187             : 
     188           0 :     } else if (!strcmp(name, "pacemaker-fenced")) {
     189           0 :         return "stonith-ng";
     190             : 
     191           0 :     } else if (!strcmp(name, "pacemaker-schedulerd")) {
     192           0 :         return CRM_SYSTEM_PENGINE;
     193             : 
     194             :     } else {
     195           0 :         return name;
     196             :     }
     197             : }
     198             : 
     199             : /*!
     200             :  * \internal
     201             :  * \brief Register handlers for server commands
     202             :  *
     203             :  * \param[in] handlers  Array of handler functions for supported server commands
     204             :  *                      (the final entry must have a NULL command name, and if
     205             :  *                      it has a handler it will be used as the default handler
     206             :  *                      for unrecognized commands)
     207             :  *
     208             :  * \return Newly created hash table with commands and handlers
     209             :  * \note The caller is responsible for freeing the return value with
     210             :  *       g_hash_table_destroy().
     211             :  */
     212             : GHashTable *
     213           0 : pcmk__register_handlers(const pcmk__server_command_t handlers[])
     214             : {
     215           0 :     GHashTable *commands = g_hash_table_new(g_str_hash, g_str_equal);
     216             : 
     217           0 :     if (handlers != NULL) {
     218             :         int i;
     219             : 
     220           0 :         for (i = 0; handlers[i].command != NULL; ++i) {
     221           0 :             g_hash_table_insert(commands, (gpointer) handlers[i].command,
     222           0 :                                 handlers[i].handler);
     223             :         }
     224           0 :         if (handlers[i].handler != NULL) {
     225             :             // g_str_hash() can't handle NULL, so use empty string for default
     226           0 :             g_hash_table_insert(commands, (gpointer) "", handlers[i].handler);
     227             :         }
     228             :     }
     229           0 :     return commands;
     230             : }
     231             : 
     232             : /*!
     233             :  * \internal
     234             :  * \brief Process an incoming request
     235             :  *
     236             :  * \param[in,out] request   Request to process
     237             :  * \param[in]     handlers  Command table created by pcmk__register_handlers()
     238             :  *
     239             :  * \return XML to send as reply (or NULL if no reply is needed)
     240             :  */
     241             : xmlNode *
     242           0 : pcmk__process_request(pcmk__request_t *request, GHashTable *handlers)
     243             : {
     244           0 :     xmlNode *(*handler)(pcmk__request_t *request) = NULL;
     245             : 
     246           0 :     CRM_CHECK((request != NULL) && (request->op != NULL) && (handlers != NULL),
     247             :               return NULL);
     248             : 
     249           0 :     if (pcmk_is_set(request->flags, pcmk__request_sync)
     250           0 :         && (request->ipc_client != NULL)) {
     251           0 :         CRM_CHECK(request->ipc_client->request_id == request->ipc_id,
     252             :                   return NULL);
     253             :     }
     254             : 
     255           0 :     handler = g_hash_table_lookup(handlers, request->op);
     256           0 :     if (handler == NULL) {
     257           0 :         handler = g_hash_table_lookup(handlers, ""); // Default handler
     258           0 :         if (handler == NULL) {
     259           0 :             crm_info("Ignoring %s request from %s %s with no handler",
     260             :                      request->op, pcmk__request_origin_type(request),
     261             :                      pcmk__request_origin(request));
     262           0 :             return NULL;
     263             :         }
     264             :     }
     265             : 
     266           0 :     return (*handler)(request);
     267             : }
     268             : 
     269             : /*!
     270             :  * \internal
     271             :  * \brief Free memory used within a request (but not the request itself)
     272             :  *
     273             :  * \param[in,out] request  Request to reset
     274             :  */
     275             : void
     276           0 : pcmk__reset_request(pcmk__request_t *request)
     277             : {
     278           0 :     free(request->op);
     279           0 :     request->op = NULL;
     280             : 
     281           0 :     pcmk__reset_result(&(request->result));
     282           0 : }
     283             : 
     284             : // Deprecated functions kept only for backward API compatibility
     285             : // LCOV_EXCL_START
     286             : 
     287             : #include <crm/common/xml_compat.h>
     288             : 
     289             : gboolean
     290             : add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
     291             : {
     292             :     xmlNode *holder = pcmk__xe_create(msg, field);
     293             : 
     294             :     pcmk__xml_copy(holder, xml);
     295             :     return TRUE;
     296             : }
     297             : 
     298             : xmlNode *
     299             : get_message_xml(const xmlNode *msg, const char *field)
     300             : {
     301             :     xmlNode *child = pcmk__xe_first_child(msg, field, NULL, NULL);
     302             : 
     303             :     return pcmk__xe_first_child(child, NULL, NULL, NULL);
     304             : }
     305             : 
     306             : // LCOV_EXCL_STOP
     307             : // End deprecated API

Generated by: LCOV version 1.14