Page MenuHomeClusterLabs Projects

messages.c
No OneTemporary

messages.c

/*
* Copyright 2004-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <time.h> // time()
#include <sys/types.h>
#include <glib.h>
#include <libxml/tree.h>
#include <crm/common/xml.h>
#include <crm/common/xml_internal.h>
/*!
* \internal
* \brief Create message XML (for IPC or the cluster layer)
*
* Create standard, generic XML that can be used as a message sent via IPC or
* the cluster layer. Currently, not all IPC and cluster layer messaging uses
* this, but it should (eventually, keeping backward compatibility in mind).
*
* \param[in] origin Name of function that called this one (required)
* \param[in] server Server whose protocol defines message semantics
* \param[in] reply_to If NULL, create message as a request with a
* generated message ID, otherwise create message
* as a reply to this message ID
* \param[in] sender_system Sender's subsystem (required; this is an
* arbitrary string that may have meaning between
* the sender and recipient)
* \param[in] recipient_node If not NULL, add as message's recipient node
* (NULL typically indicates a broadcast message)
* \param[in] recipient_system If not NULL, add as message's recipient
* subsystem (this is an arbitrary string that may
* have meaning between the sender and recipient)
* \param[in] task Add as message's task (required)
* \param[in] data If not NULL, copy as message's data (callers
* should not add attributes to the returned
* message element, but instead pass any desired
* information here, though this is not always
* honored currently)
*
* \return Newly created message XML
*
* \note This function should usually not be called directly, but via the
* pcmk__new_message() wrapper.
* \note The caller is responsible for freeing the return value using
* \c pcmk__xml_free().
*/
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)
{
static unsigned int message_counter = 0U;
xmlNode *message = NULL;
char *message_id = NULL;
const char *subtype = PCMK__VALUE_RESPONSE;
CRM_CHECK(!pcmk__str_empty(origin)
&& !pcmk__str_empty(sender_system)
&& !pcmk__str_empty(task),
return NULL);
if (reply_to == NULL) {
subtype = PCMK__VALUE_REQUEST;
message_id = crm_strdup_printf("%s-%s-%llu-%u", task, sender_system,
(unsigned long long) time(NULL),
message_counter++);
reply_to = message_id;
}
message = pcmk__xe_create(NULL, PCMK__XE_MESSAGE);
pcmk__xe_set_props(message,
PCMK_XA_ORIGIN, origin,
PCMK__XA_T, pcmk__server_message_type(server),
PCMK__XA_SUBT, subtype,
PCMK_XA_VERSION, CRM_FEATURE_SET,
PCMK_XA_REFERENCE, reply_to,
PCMK__XA_CRM_SYS_FROM, sender_system,
PCMK__XA_CRM_HOST_TO, recipient_node,
PCMK__XA_CRM_SYS_TO, recipient_system,
PCMK__XA_CRM_TASK, task,
NULL);
if (data != NULL) {
xmlNode *wrapper = pcmk__xe_create(message, PCMK__XE_CRM_XML);
pcmk__xml_copy(wrapper, data);
}
free(message_id);
return message;
}
/*!
* \internal
* \brief Create a Pacemaker reply (for IPC or cluster layer)
*
* \param[in] origin Name of function that called this one
* \param[in] original_request XML of request being replied to
* \param[in] data If not NULL, copy as reply's data (callers
* should not add attributes to the returned
* message element, but instead pass any desired
* information here, though this is not always
* honored currently)
*
* \return Newly created reply XML
*
* \note This function should not be called directly, but via the
* pcmk__new_reply() wrapper.
* \note The caller is responsible for freeing the return value using
* \c pcmk__xml_free().
*/
xmlNode *
pcmk__new_reply_as(const char *origin, const xmlNode *original_request,
xmlNode *data)
{
const char *message_type = crm_element_value(original_request, PCMK__XA_T);
const char *host_from = crm_element_value(original_request, PCMK__XA_SRC);
const char *sys_from = crm_element_value(original_request,
PCMK__XA_CRM_SYS_FROM);
const char *sys_to = crm_element_value(original_request,
PCMK__XA_CRM_SYS_TO);
const char *type = crm_element_value(original_request, PCMK__XA_SUBT);
const char *operation = crm_element_value(original_request,
PCMK__XA_CRM_TASK);
const char *crm_msg_reference = crm_element_value(original_request,
PCMK_XA_REFERENCE);
enum pcmk_ipc_server server = pcmk__parse_server(message_type);
if (server == pcmk_ipc_unknown) {
/* @COMPAT Not all requests currently specify a message type, so use a
* default that preserves past behavior.
*
* @TODO Ensure all requests specify a message type, drop this check
* after we no longer support rolling upgrades or Pacemaker Remote
* connections involving versions before that.
*/
server = pcmk_ipc_controld;
}
if (type == NULL) {
crm_warn("Cannot reply to invalid message: No message type specified");
return NULL;
}
if (strcmp(type, PCMK__VALUE_REQUEST) != 0) {
/* Replies should only be generated for request messages, but it's possible
* we expect replies to other messages right now so this can't be enforced.
*/
crm_trace("Creating a reply for a non-request original message");
}
// Since this is a reply, we reverse the sender and recipient info
return pcmk__new_message_as(origin, server, crm_msg_reference, sys_to,
host_from, sys_from, operation, data);
}
/*!
* \internal
* \brief Register handlers for server commands
*
* \param[in] handlers Array of handler functions for supported server commands
* (the final entry must have a NULL command name, and if
* it has a handler it will be used as the default handler
* for unrecognized commands)
*
* \return Newly created hash table with commands and handlers
* \note The caller is responsible for freeing the return value with
* g_hash_table_destroy().
*/
GHashTable *
pcmk__register_handlers(const pcmk__server_command_t handlers[])
{
GHashTable *commands = g_hash_table_new(g_str_hash, g_str_equal);
if (handlers != NULL) {
int i;
for (i = 0; handlers[i].command != NULL; ++i) {
g_hash_table_insert(commands, (gpointer) handlers[i].command,
handlers[i].handler);
}
if (handlers[i].handler != NULL) {
// g_str_hash() can't handle NULL, so use empty string for default
g_hash_table_insert(commands, (gpointer) "", handlers[i].handler);
}
}
return commands;
}
/*!
* \internal
* \brief Process an incoming request
*
* \param[in,out] request Request to process
* \param[in] handlers Command table created by pcmk__register_handlers()
*
* \return XML to send as reply (or NULL if no reply is needed)
*/
xmlNode *
pcmk__process_request(pcmk__request_t *request, GHashTable *handlers)
{
xmlNode *(*handler)(pcmk__request_t *request) = NULL;
CRM_CHECK((request != NULL) && (request->op != NULL) && (handlers != NULL),
return NULL);
if (pcmk_is_set(request->flags, pcmk__request_sync)
&& (request->ipc_client != NULL)) {
CRM_CHECK(request->ipc_client->request_id == request->ipc_id,
return NULL);
}
handler = g_hash_table_lookup(handlers, request->op);
if (handler == NULL) {
handler = g_hash_table_lookup(handlers, ""); // Default handler
if (handler == NULL) {
crm_info("Ignoring %s request from %s %s with no handler",
request->op, pcmk__request_origin_type(request),
pcmk__request_origin(request));
return NULL;
}
}
return (*handler)(request);
}
/*!
* \internal
* \brief Free memory used within a request (but not the request itself)
*
* \param[in,out] request Request to reset
*/
void
pcmk__reset_request(pcmk__request_t *request)
{
free(request->op);
request->op = NULL;
pcmk__reset_result(&(request->result));
}

File Metadata

Mime Type
text/x-c
Expires
Wed, Jun 25, 5:27 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1946186
Default Alt Text
messages.c (9 KB)

Event Timeline