Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512439
messages.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
messages.c
View Options
/*
* 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
Details
Attached
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)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment