root/lib/cib/cib_native.c

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

DEFINITIONS

This source file includes following definitions.
  1. cib_native_new
  2. cib_native_signon
  3. cib_native_dispatch_internal
  4. cib_native_destroy
  5. cib_native_signon_raw
  6. cib_native_signoff
  7. cib_native_free
  8. cib_native_perform_op
  9. cib_native_perform_op_delegate
  10. cib_native_set_connection_dnotify
  11. cib_native_register_notification

   1 /*
   2  * Copyright 2004 International Business Machines
   3  * Later changes copyright 2004-2021 the Pacemaker project contributors
   4  *
   5  * The version control history for this file may have further details.
   6  *
   7  * This source code is licensed under the GNU Lesser General Public License
   8  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   9  */
  10 
  11 #include <crm_internal.h>
  12 
  13 #ifndef _GNU_SOURCE
  14 #  define _GNU_SOURCE
  15 #endif
  16 
  17 #include <errno.h>
  18 #include <crm_internal.h>
  19 #include <unistd.h>
  20 #include <stdlib.h>
  21 #include <stdio.h>
  22 #include <stdarg.h>
  23 #include <string.h>
  24 
  25 #include <glib.h>
  26 
  27 #include <crm/crm.h>
  28 #include <crm/cib/internal.h>
  29 
  30 #include <crm/msg_xml.h>
  31 #include <crm/common/mainloop.h>
  32 
  33 typedef struct cib_native_opaque_s {
  34     char *token;
  35     crm_ipc_t *ipc;
  36     void (*dnotify_fn) (gpointer user_data);
  37     mainloop_io_t *source;
  38 
  39 } cib_native_opaque_t;
  40 
  41 int cib_native_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
  42                           xmlNode * data, xmlNode ** output_data, int call_options);
  43 
  44 int cib_native_perform_op_delegate(cib_t * cib, const char *op, const char *host,
  45                                    const char *section, xmlNode * data, xmlNode ** output_data,
  46                                    int call_options, const char *user_name);
  47 
  48 int cib_native_free(cib_t * cib);
  49 int cib_native_signoff(cib_t * cib);
  50 int cib_native_signon(cib_t * cib, const char *name, enum cib_conn_type type);
  51 int cib_native_signon_raw(cib_t * cib, const char *name, enum cib_conn_type type, int *event_fd);
  52 
  53 int cib_native_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data));
  54 
  55 cib_t *
  56 cib_native_new(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58     cib_native_opaque_t *native = NULL;
  59     cib_t *cib = cib_new_variant();
  60 
  61     if (cib == NULL) {
  62         return NULL;
  63     }
  64 
  65     native = calloc(1, sizeof(cib_native_opaque_t));
  66 
  67     if (native == NULL) {
  68         free(cib);
  69         return NULL;
  70     }
  71 
  72     cib->variant = cib_native;
  73     cib->variant_opaque = native;
  74 
  75     native->ipc = NULL;
  76     native->source = NULL;
  77     native->dnotify_fn = NULL;
  78 
  79     /* assign variant specific ops */
  80     cib->delegate_fn = cib_native_perform_op_delegate;
  81     cib->cmds->signon = cib_native_signon;
  82     cib->cmds->signon_raw = cib_native_signon_raw;
  83     cib->cmds->signoff = cib_native_signoff;
  84     cib->cmds->free = cib_native_free;
  85 
  86     cib->cmds->register_notification = cib_native_register_notification;
  87     cib->cmds->set_connection_dnotify = cib_native_set_connection_dnotify;
  88 
  89     return cib;
  90 }
  91 
  92 int
  93 cib_native_signon(cib_t * cib, const char *name, enum cib_conn_type type)
     /* [previous][next][first][last][top][bottom][index][help] */
  94 {
  95     return cib_native_signon_raw(cib, name, type, NULL);
  96 }
  97 
  98 static int
  99 cib_native_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101     const char *type = NULL;
 102     xmlNode *msg = NULL;
 103 
 104     cib_t *cib = userdata;
 105 
 106     crm_trace("dispatching %p", userdata);
 107 
 108     if (cib == NULL) {
 109         crm_err("No CIB!");
 110         return 0;
 111     }
 112 
 113     msg = string2xml(buffer);
 114 
 115     if (msg == NULL) {
 116         crm_warn("Received a NULL message from the CIB manager");
 117         return 0;
 118     }
 119 
 120     /* do callbacks */
 121     type = crm_element_value(msg, F_TYPE);
 122     crm_trace("Activating %s callbacks...", type);
 123     crm_log_xml_explicit(msg, "cib-reply");
 124 
 125     if (pcmk__str_eq(type, T_CIB, pcmk__str_casei)) {
 126         cib_native_callback(cib, msg, 0, 0);
 127 
 128     } else if (pcmk__str_eq(type, T_CIB_NOTIFY, pcmk__str_casei)) {
 129         g_list_foreach(cib->notify_list, cib_native_notify, msg);
 130 
 131     } else {
 132         crm_err("Unknown message type: %s", type);
 133     }
 134 
 135     free_xml(msg);
 136     return 0;
 137 }
 138 
 139 static void
 140 cib_native_destroy(void *userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 141 {
 142     cib_t *cib = userdata;
 143     cib_native_opaque_t *native = cib->variant_opaque;
 144 
 145     crm_trace("destroying %p", userdata);
 146     cib->state = cib_disconnected;
 147     native->source = NULL;
 148     native->ipc = NULL;
 149 
 150     if (native->dnotify_fn) {
 151         native->dnotify_fn(userdata);
 152     }
 153 }
 154 
 155 int
 156 cib_native_signon_raw(cib_t * cib, const char *name, enum cib_conn_type type, int *async_fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158     int rc = pcmk_ok;
 159     const char *channel = NULL;
 160     cib_native_opaque_t *native = cib->variant_opaque;
 161 
 162     struct ipc_client_callbacks cib_callbacks = {
 163         .dispatch = cib_native_dispatch_internal,
 164         .destroy = cib_native_destroy
 165     };
 166 
 167     cib->call_timeout = PCMK__IPC_TIMEOUT;
 168 
 169     if (type == cib_command) {
 170         cib->state = cib_connected_command;
 171         channel = PCMK__SERVER_BASED_RW;
 172 
 173     } else if (type == cib_command_nonblocking) {
 174         cib->state = cib_connected_command;
 175         channel = PCMK__SERVER_BASED_SHM;
 176 
 177     } else if (type == cib_query) {
 178         cib->state = cib_connected_query;
 179         channel = PCMK__SERVER_BASED_RO;
 180 
 181     } else {
 182         return -ENOTCONN;
 183     }
 184 
 185     crm_trace("Connecting %s channel", channel);
 186 
 187     if (async_fd != NULL) {
 188         native->ipc = crm_ipc_new(channel, 0);
 189 
 190         if (native->ipc && crm_ipc_connect(native->ipc)) {
 191             *async_fd = crm_ipc_get_fd(native->ipc);
 192 
 193         } else if (native->ipc) {
 194             rc = -ENOTCONN;
 195         }
 196 
 197     } else {
 198         native->source =
 199             mainloop_add_ipc_client(channel, G_PRIORITY_HIGH, 512 * 1024 /* 512k */ , cib,
 200                                     &cib_callbacks);
 201         native->ipc = mainloop_get_ipc_client(native->source);
 202     }
 203 
 204     if (rc != pcmk_ok || native->ipc == NULL || crm_ipc_connected(native->ipc) == FALSE) {
 205         crm_info("Could not connect to CIB manager for %s", name);
 206         rc = -ENOTCONN;
 207     }
 208 
 209     if (rc == pcmk_ok) {
 210         xmlNode *reply = NULL;
 211         xmlNode *hello = create_xml_node(NULL, "cib_command");
 212 
 213         crm_xml_add(hello, F_TYPE, T_CIB);
 214         crm_xml_add(hello, F_CIB_OPERATION, CRM_OP_REGISTER);
 215         crm_xml_add(hello, F_CIB_CLIENTNAME, name);
 216         crm_xml_add_int(hello, F_CIB_CALLOPTS, cib_sync_call);
 217 
 218         if (crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply) > 0) {
 219             const char *msg_type = crm_element_value(reply, F_CIB_OPERATION);
 220 
 221             rc = pcmk_ok;
 222             crm_log_xml_trace(reply, "reg-reply");
 223 
 224             if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
 225                 crm_info("Reply to CIB registration message has "
 226                          "unknown type '%s'", msg_type);
 227                 rc = -EPROTO;
 228 
 229             } else {
 230                 native->token = crm_element_value_copy(reply, F_CIB_CLIENTID);
 231                 if (native->token == NULL) {
 232                     rc = -EPROTO;
 233                 }
 234             }
 235             free_xml(reply);
 236 
 237         } else {
 238             rc = -ECOMM;
 239         }
 240 
 241         free_xml(hello);
 242     }
 243 
 244     if (rc == pcmk_ok) {
 245         crm_info("Successfully connected to CIB manager for %s", name);
 246         return pcmk_ok;
 247     }
 248 
 249     crm_info("Connection to CIB manager for %s failed: %s",
 250              name, pcmk_strerror(rc));
 251     cib_native_signoff(cib);
 252     return rc;
 253 }
 254 
 255 int
 256 cib_native_signoff(cib_t * cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258     cib_native_opaque_t *native = cib->variant_opaque;
 259 
 260     crm_debug("Disconnecting from the CIB manager");
 261 
 262     cib_free_notify(cib);
 263     remove_cib_op_callback(0, TRUE);
 264 
 265     if (native->source != NULL) {
 266         /* Attached to mainloop */
 267         mainloop_del_ipc_client(native->source);
 268         native->source = NULL;
 269         native->ipc = NULL;
 270 
 271     } else if (native->ipc) {
 272         /* Not attached to mainloop */
 273         crm_ipc_t *ipc = native->ipc;
 274 
 275         native->ipc = NULL;
 276         crm_ipc_close(ipc);
 277         crm_ipc_destroy(ipc);
 278     }
 279 
 280     cib->state = cib_disconnected;
 281     cib->type = cib_no_connection;
 282 
 283     return pcmk_ok;
 284 }
 285 
 286 int
 287 cib_native_free(cib_t * cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289     int rc = pcmk_ok;
 290 
 291     if (cib->state != cib_disconnected) {
 292         rc = cib_native_signoff(cib);
 293     }
 294 
 295     if (cib->state == cib_disconnected) {
 296         cib_native_opaque_t *native = cib->variant_opaque;
 297 
 298         free(native->token);
 299         free(cib->variant_opaque);
 300         free(cib->cmds);
 301         free(cib);
 302     }
 303 
 304     return rc;
 305 }
 306 
 307 int
 308 cib_native_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
     /* [previous][next][first][last][top][bottom][index][help] */
 309                       xmlNode * data, xmlNode ** output_data, int call_options)
 310 {
 311     return cib_native_perform_op_delegate(cib, op, host, section,
 312                                           data, output_data, call_options, NULL);
 313 }
 314 
 315 int
 316 cib_native_perform_op_delegate(cib_t * cib, const char *op, const char *host, const char *section,
     /* [previous][next][first][last][top][bottom][index][help] */
 317                                xmlNode * data, xmlNode ** output_data, int call_options,
 318                                const char *user_name)
 319 {
 320     int rc = pcmk_ok;
 321     int reply_id = 0;
 322     enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
 323 
 324     xmlNode *op_msg = NULL;
 325     xmlNode *op_reply = NULL;
 326 
 327     cib_native_opaque_t *native = cib->variant_opaque;
 328 
 329     if (cib->state == cib_disconnected) {
 330         return -ENOTCONN;
 331     }
 332 
 333     if (output_data != NULL) {
 334         *output_data = NULL;
 335     }
 336 
 337     if (op == NULL) {
 338         crm_err("No operation specified");
 339         return -EINVAL;
 340     }
 341 
 342     if (call_options & cib_sync_call) {
 343         pcmk__set_ipc_flags(ipc_flags, "client", crm_ipc_client_response);
 344     }
 345 
 346     cib->call_id++;
 347     if (cib->call_id < 1) {
 348         cib->call_id = 1;
 349     }
 350 
 351     CRM_CHECK(native->token != NULL,;
 352         );
 353     op_msg =
 354         cib_create_op(cib->call_id, native->token, op, host, section, data, call_options,
 355                       user_name);
 356     if (op_msg == NULL) {
 357         return -EPROTO;
 358     }
 359 
 360     crm_trace("Sending %s message to the CIB manager (timeout=%ds)", op, cib->call_timeout);
 361     rc = crm_ipc_send(native->ipc, op_msg, ipc_flags, cib->call_timeout * 1000, &op_reply);
 362     free_xml(op_msg);
 363 
 364     if (rc < 0) {
 365         crm_err("Couldn't perform %s operation (timeout=%ds): %s (%d)", op,
 366                 cib->call_timeout, pcmk_strerror(rc), rc);
 367         rc = -ECOMM;
 368         goto done;
 369     }
 370 
 371     crm_log_xml_trace(op_reply, "Reply");
 372 
 373     if (!(call_options & cib_sync_call)) {
 374         crm_trace("Async call, returning %d", cib->call_id);
 375         CRM_CHECK(cib->call_id != 0, return -ENOMSG);
 376         free_xml(op_reply);
 377         return cib->call_id;
 378     }
 379 
 380     rc = pcmk_ok;
 381     crm_element_value_int(op_reply, F_CIB_CALLID, &reply_id);
 382     if (reply_id == cib->call_id) {
 383         xmlNode *tmp = get_message_xml(op_reply, F_CIB_CALLDATA);
 384 
 385         crm_trace("Synchronous reply %d received", reply_id);
 386         if (crm_element_value_int(op_reply, F_CIB_RC, &rc) != 0) {
 387             rc = -EPROTO;
 388         }
 389 
 390         if (output_data == NULL || (call_options & cib_discard_reply)) {
 391             crm_trace("Discarding reply");
 392 
 393         } else if (tmp != NULL) {
 394             *output_data = copy_xml(tmp);
 395         }
 396 
 397     } else if (reply_id <= 0) {
 398         crm_err("Received bad reply: No id set");
 399         crm_log_xml_err(op_reply, "Bad reply");
 400         rc = -ENOMSG;
 401         goto done;
 402 
 403     } else {
 404         crm_err("Received bad reply: %d (wanted %d)", reply_id, cib->call_id);
 405         crm_log_xml_err(op_reply, "Old reply");
 406         rc = -ENOMSG;
 407         goto done;
 408     }
 409 
 410     if (op_reply == NULL && cib->state == cib_disconnected) {
 411         rc = -ENOTCONN;
 412 
 413     } else if (rc == pcmk_ok && op_reply == NULL) {
 414         rc = -ETIME;
 415     }
 416 
 417     switch (rc) {
 418         case pcmk_ok:
 419         case -EPERM:
 420             break;
 421 
 422             /* This is an internal value that clients do not and should not care about */
 423         case -pcmk_err_diff_resync:
 424             rc = pcmk_ok;
 425             break;
 426 
 427             /* These indicate internal problems */
 428         case -EPROTO:
 429         case -ENOMSG:
 430             crm_err("Call failed: %s", pcmk_strerror(rc));
 431             if (op_reply) {
 432                 crm_log_xml_err(op_reply, "Invalid reply");
 433             }
 434             break;
 435 
 436         default:
 437             if (!pcmk__str_eq(op, CIB_OP_QUERY, pcmk__str_casei)) {
 438                 crm_warn("Call failed: %s", pcmk_strerror(rc));
 439             }
 440     }
 441 
 442   done:
 443     if (crm_ipc_connected(native->ipc) == FALSE) {
 444         crm_err("The CIB manager disconnected");
 445         cib->state = cib_disconnected;
 446     }
 447 
 448     free_xml(op_reply);
 449     return rc;
 450 }
 451 
 452 int
 453 cib_native_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
     /* [previous][next][first][last][top][bottom][index][help] */
 454 {
 455     cib_native_opaque_t *native = NULL;
 456 
 457     if (cib == NULL) {
 458         crm_err("No CIB!");
 459         return FALSE;
 460     }
 461 
 462     native = cib->variant_opaque;
 463     native->dnotify_fn = dnotify;
 464 
 465     return pcmk_ok;
 466 }
 467 
 468 int
 469 cib_native_register_notification(cib_t * cib, const char *callback, int enabled)
     /* [previous][next][first][last][top][bottom][index][help] */
 470 {
 471     int rc = pcmk_ok;
 472     xmlNode *notify_msg = create_xml_node(NULL, "cib-callback");
 473     cib_native_opaque_t *native = cib->variant_opaque;
 474 
 475     if (cib->state != cib_disconnected) {
 476         crm_xml_add(notify_msg, F_CIB_OPERATION, T_CIB_NOTIFY);
 477         crm_xml_add(notify_msg, F_CIB_NOTIFY_TYPE, callback);
 478         crm_xml_add_int(notify_msg, F_CIB_NOTIFY_ACTIVATE, enabled);
 479         rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response,
 480                           1000 * cib->call_timeout, NULL);
 481         if (rc <= 0) {
 482             crm_trace("Notification not registered: %d", rc);
 483             rc = -ECOMM;
 484         }
 485     }
 486 
 487     free_xml(notify_msg);
 488     return rc;
 489 }

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