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

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