root/lib/common/ipc_common.c

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

DEFINITIONS

This source file includes following definitions.
  1. crm_ipc_default_buffer_size
  2. pcmk__valid_ipc_header
  3. pcmk__client_type_str
  4. pcmk__ipc_msg_append

   1 /*
   2  * Copyright 2004-2025 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 <stdint.h>         // uint64_t
  14 #include <sys/types.h>
  15 
  16 #include <crm/common/xml.h>
  17 #include "crmcommon_private.h"
  18 
  19 /* The IPC buffer is always 128k.  If we are asked to send a message larger
  20  * than that size, it will be split into multiple messages that must be
  21  * reassembled on the other end.
  22  */
  23 #define BUFFER_SIZE     (128*1024) // 128k
  24 
  25 /*!
  26  * \brief Return pacemaker's IPC buffer size
  27  *
  28  * \return IPC buffer size in bytes
  29  */
  30 unsigned int
  31 crm_ipc_default_buffer_size(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33     return BUFFER_SIZE;
  34 }
  35 
  36 /*!
  37  * \internal
  38  * \brief Check whether an IPC header is valid
  39  *
  40  * \param[in] header  IPC header to check
  41  *
  42  * \return true if IPC header has a supported version, false otherwise
  43  */
  44 bool
  45 pcmk__valid_ipc_header(const pcmk__ipc_header_t *header)
     /* [previous][next][first][last][top][bottom][index][help] */
  46 {
  47     if (header == NULL) {
  48         crm_err("IPC message without header");
  49         return false;
  50 
  51     } else if (header->version > PCMK__IPC_VERSION) {
  52         crm_err("Filtering incompatible v%d IPC message (only versions <= %d supported)",
  53                 header->version, PCMK__IPC_VERSION);
  54         return false;
  55     }
  56     return true;
  57 }
  58 
  59 const char *
  60 pcmk__client_type_str(uint64_t client_type)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62     switch (client_type) {
  63         case pcmk__client_ipc:
  64             return "IPC";
  65         case pcmk__client_tcp:
  66             return "TCP";
  67         case pcmk__client_tls:
  68             return "TLS";
  69         default:
  70             return "unknown";
  71     }
  72 }
  73 
  74 /*!
  75  * \internal
  76  * \brief Add more data to a received partial IPC message
  77  *
  78  * This function can be called repeatedly to build up a complete IPC message
  79  * from smaller parts.  It does this by inspecting flags on the message.
  80  * Most of the time, IPC messages will be small enough where this function
  81  * won't get called more than once, but more complex clusters can end up with
  82  * very large IPC messages that don't fit in a single buffer.
  83  *
  84  * Important return values:
  85  *
  86  * - EBADMSG - Something was wrong with the data.
  87  * - pcmk_rc_ipc_more - \p data was a chunk of a partial message and there is
  88  *                      more to come.  The caller should not process the message
  89  *                      yet and should continue reading from the IPC connection.
  90  * - pcmk_rc_ok - We have the complete message.  The caller should process
  91  *                it and free the buffer to prepare for the next message.
  92  *
  93  * \param[in,out] buffer The buffer to add this data to
  94  * \param[in]     data   The received IPC message or message portion.
  95  *
  96  * \return Standard Pacemaker return code
  97  */
  98 int
  99 pcmk__ipc_msg_append(GByteArray **buffer, guint8 *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101     pcmk__ipc_header_t *full_header = NULL;
 102     pcmk__ipc_header_t *header = (pcmk__ipc_header_t *) (void *) data;
 103     const guint8 *payload = (guint8 *) data + sizeof(pcmk__ipc_header_t);
 104     int rc = pcmk_rc_ok;
 105 
 106     if (!pcmk__valid_ipc_header(header)) {
 107         return EBADMSG;
 108     }
 109 
 110     if (pcmk_is_set(header->flags, crm_ipc_multipart_end)) {
 111         full_header = (pcmk__ipc_header_t *) (void *) (*buffer)->data;
 112 
 113         /* This is the end of a multipart IPC message.  Add the payload of the
 114          * received data (so, don't include the header) to the partial buffer.
 115          * Remember that this needs to include the null terminating character.
 116          */
 117         CRM_CHECK(buffer != NULL && *buffer != NULL && header->part_id != 0,
 118                   return EINVAL);
 119         CRM_CHECK(full_header->qb.id == header->qb.id, return EBADMSG);
 120         g_byte_array_append(*buffer, payload, header->size);
 121 
 122         crm_trace("Received IPC message %" PRId32 " (final part %" PRIu16 ") of %"
 123                   PRId32 " bytes",
 124                   header->qb.id, header->part_id, header->qb.size);
 125 
 126     } else if (pcmk_is_set(header->flags, crm_ipc_multipart)) {
 127         if (header->part_id == 0) {
 128             /* This is the first part of a multipart IPC message.  Initialize
 129              * the buffer with the entire message, including its header.  Do
 130              * not include the null terminating character.
 131              */
 132             CRM_CHECK(buffer != NULL && *buffer == NULL, return EINVAL);
 133             *buffer = g_byte_array_new();
 134 
 135             /* Clear any multipart flags from the header of the incoming part
 136              * so they'll be clear in the fully reassembled message.  This
 137              * message is passed to pcmk__client_data2xml, which will extract
 138              * the header flags and return them.  Those flags can then be used
 139              * when constructing a reply, including ACKs.  We don't want these
 140              * specific incoming flags to influence the reply.
 141              */
 142             pcmk__clear_ipc_flags(header->flags, "server", crm_ipc_multipart);
 143 
 144             g_byte_array_append(*buffer, data,
 145                                 sizeof(pcmk__ipc_header_t) + header->size - 1);
 146 
 147         } else {
 148             full_header = (pcmk__ipc_header_t *) (void *) (*buffer)->data;
 149 
 150             /* This is some intermediate part of a multipart message.  Add
 151              * the payload of the received data (so, don't include the header)
 152              * to the partial buffer and return.  Do not include the null
 153              * terminating character.
 154              */
 155             CRM_CHECK(buffer != NULL && *buffer != NULL, return EINVAL);
 156             CRM_CHECK(full_header->qb.id == header->qb.id, return EBADMSG);
 157             g_byte_array_append(*buffer, payload, header->size - 1);
 158         }
 159 
 160         crm_trace("Received IPC message %" PRId32 " (part %" PRIu16 ") of %"
 161                   PRId32 " bytes",
 162                   header->qb.id, header->part_id, header->qb.size);
 163 
 164         rc = pcmk_rc_ipc_more;
 165 
 166     } else {
 167         /* This is a standalone IPC message.  For simplicity in the caller,
 168          * copy the entire message over into a byte array so it can be handled
 169          * the same as a multipart message.
 170          */
 171         CRM_CHECK(buffer != NULL && *buffer == NULL, return EINVAL);
 172         *buffer = g_byte_array_new();
 173         g_byte_array_append(*buffer, data,
 174                             sizeof(pcmk__ipc_header_t) + header->size);
 175 
 176         crm_trace("Received IPC message %" PRId32 " of %" PRId32 " bytes",
 177                   header->qb.id, header->qb.size);
 178     }
 179 
 180     crm_trace("Text = %s", payload);
 181     crm_trace("Buffer = %s", (*buffer)->data + sizeof(pcmk__ipc_header_t));
 182 
 183     /* The buffer's header should have a size that matches the full size of
 184      * the received message, not just the last chunk of it.
 185      */
 186     full_header = (pcmk__ipc_header_t *) (void *) (*buffer)->data;
 187     full_header->size = (*buffer)->len - sizeof(pcmk__ipc_header_t);
 188 
 189     return rc;
 190 }

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