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-2020 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 = MAX_IPC_DELAY;
 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     if (native->source != NULL) {
 254         /* Attached to mainloop */
 255         mainloop_del_ipc_client(native->source);
 256         native->source = NULL;
 257         native->ipc = NULL;
 258 
 259     } else if (native->ipc) {
 260         /* Not attached to mainloop */
 261         crm_ipc_t *ipc = native->ipc;
 262 
 263         native->ipc = NULL;
 264         crm_ipc_close(ipc);
 265         crm_ipc_destroy(ipc);
 266     }
 267 
 268     cib->state = cib_disconnected;
 269     cib->type = cib_no_connection;
 270 
 271     return pcmk_ok;
 272 }
 273 
 274 int
 275 cib_native_free(cib_t * cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277     int rc = pcmk_ok;
 278 
 279     if (cib->state != cib_disconnected) {
 280         rc = cib_native_signoff(cib);
 281     }
 282 
 283     if (cib->state == cib_disconnected) {
 284         cib_native_opaque_t *native = cib->variant_opaque;
 285 
 286         free(native->token);
 287         free(cib->variant_opaque);
 288         free(cib->cmds);
 289         free(cib);
 290     }
 291 
 292     return rc;
 293 }
 294 
 295 int
 296 cib_native_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
     /* [previous][next][first][last][top][bottom][index][help] */
 297                       xmlNode * data, xmlNode ** output_data, int call_options)
 298 {
 299     return cib_native_perform_op_delegate(cib, op, host, section,
 300                                           data, output_data, call_options, NULL);
 301 }
 302 
 303 int
 304 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] */
 305                                xmlNode * data, xmlNode ** output_data, int call_options,
 306                                const char *user_name)
 307 {
 308     int rc = pcmk_ok;
 309     int reply_id = 0;
 310     enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
 311 
 312     xmlNode *op_msg = NULL;
 313     xmlNode *op_reply = NULL;
 314 
 315     cib_native_opaque_t *native = cib->variant_opaque;
 316 
 317     if (cib->state == cib_disconnected) {
 318         return -ENOTCONN;
 319     }
 320 
 321     if (output_data != NULL) {
 322         *output_data = NULL;
 323     }
 324 
 325     if (op == NULL) {
 326         crm_err("No operation specified");
 327         return -EINVAL;
 328     }
 329 
 330     if (call_options & cib_sync_call) {
 331         pcmk__set_ipc_flags(ipc_flags, "client", crm_ipc_client_response);
 332     }
 333 
 334     cib->call_id++;
 335     if (cib->call_id < 1) {
 336         cib->call_id = 1;
 337     }
 338 
 339     CRM_CHECK(native->token != NULL,;
 340         );
 341     op_msg =
 342         cib_create_op(cib->call_id, native->token, op, host, section, data, call_options,
 343                       user_name);
 344     if (op_msg == NULL) {
 345         return -EPROTO;
 346     }
 347 
 348     crm_trace("Sending %s message to the CIB manager (timeout=%ds)", op, cib->call_timeout);
 349     rc = crm_ipc_send(native->ipc, op_msg, ipc_flags, cib->call_timeout * 1000, &op_reply);
 350     free_xml(op_msg);
 351 
 352     if (rc < 0) {
 353         crm_err("Couldn't perform %s operation (timeout=%ds): %s (%d)", op,
 354                 cib->call_timeout, pcmk_strerror(rc), rc);
 355         rc = -ECOMM;
 356         goto done;
 357     }
 358 
 359     crm_log_xml_trace(op_reply, "Reply");
 360 
 361     if (!(call_options & cib_sync_call)) {
 362         crm_trace("Async call, returning %d", cib->call_id);
 363         CRM_CHECK(cib->call_id != 0, return -ENOMSG);
 364         free_xml(op_reply);
 365         return cib->call_id;
 366     }
 367 
 368     rc = pcmk_ok;
 369     crm_element_value_int(op_reply, F_CIB_CALLID, &reply_id);
 370     if (reply_id == cib->call_id) {
 371         xmlNode *tmp = get_message_xml(op_reply, F_CIB_CALLDATA);
 372 
 373         crm_trace("Synchronous reply %d received", reply_id);
 374         if (crm_element_value_int(op_reply, F_CIB_RC, &rc) != 0) {
 375             rc = -EPROTO;
 376         }
 377 
 378         if (output_data == NULL || (call_options & cib_discard_reply)) {
 379             crm_trace("Discarding reply");
 380 
 381         } else if (tmp != NULL) {
 382             *output_data = copy_xml(tmp);
 383         }
 384 
 385     } else if (reply_id <= 0) {
 386         crm_err("Received bad reply: No id set");
 387         crm_log_xml_err(op_reply, "Bad reply");
 388         rc = -ENOMSG;
 389         goto done;
 390 
 391     } else {
 392         crm_err("Received bad reply: %d (wanted %d)", reply_id, cib->call_id);
 393         crm_log_xml_err(op_reply, "Old reply");
 394         rc = -ENOMSG;
 395         goto done;
 396     }
 397 
 398     if (op_reply == NULL && cib->state == cib_disconnected) {
 399         rc = -ENOTCONN;
 400 
 401     } else if (rc == pcmk_ok && op_reply == NULL) {
 402         rc = -ETIME;
 403     }
 404 
 405     switch (rc) {
 406         case pcmk_ok:
 407         case -EPERM:
 408             break;
 409 
 410             /* This is an internal value that clients do not and should not care about */
 411         case -pcmk_err_diff_resync:
 412             rc = pcmk_ok;
 413             break;
 414 
 415             /* These indicate internal problems */
 416         case -EPROTO:
 417         case -ENOMSG:
 418             crm_err("Call failed: %s", pcmk_strerror(rc));
 419             if (op_reply) {
 420                 crm_log_xml_err(op_reply, "Invalid reply");
 421             }
 422             break;
 423 
 424         default:
 425             if (!pcmk__str_eq(op, CIB_OP_QUERY, pcmk__str_casei)) {
 426                 crm_warn("Call failed: %s", pcmk_strerror(rc));
 427             }
 428     }
 429 
 430   done:
 431     if (crm_ipc_connected(native->ipc) == FALSE) {
 432         crm_err("The CIB manager disconnected");
 433         cib->state = cib_disconnected;
 434     }
 435 
 436     free_xml(op_reply);
 437     return rc;
 438 }
 439 
 440 int
 441 cib_native_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {
 443     cib_native_opaque_t *native = NULL;
 444 
 445     if (cib == NULL) {
 446         crm_err("No CIB!");
 447         return FALSE;
 448     }
 449 
 450     native = cib->variant_opaque;
 451     native->dnotify_fn = dnotify;
 452 
 453     return pcmk_ok;
 454 }
 455 
 456 int
 457 cib_native_register_notification(cib_t * cib, const char *callback, int enabled)
     /* [previous][next][first][last][top][bottom][index][help] */
 458 {
 459     int rc = pcmk_ok;
 460     xmlNode *notify_msg = create_xml_node(NULL, "cib-callback");
 461     cib_native_opaque_t *native = cib->variant_opaque;
 462 
 463     if (cib->state != cib_disconnected) {
 464         crm_xml_add(notify_msg, F_CIB_OPERATION, T_CIB_NOTIFY);
 465         crm_xml_add(notify_msg, F_CIB_NOTIFY_TYPE, callback);
 466         crm_xml_add_int(notify_msg, F_CIB_NOTIFY_ACTIVATE, enabled);
 467         rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response,
 468                           1000 * cib->call_timeout, NULL);
 469         if (rc <= 0) {
 470             crm_trace("Notification not registered: %d", rc);
 471             rc = -ECOMM;
 472         }
 473     }
 474 
 475     free_xml(notify_msg);
 476     return rc;
 477 }

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