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_dispatch
  5. cib_native_destroy
  6. cib_native_signon_raw
  7. cib_native_signoff
  8. cib_native_free
  9. cib_native_perform_op
  10. cib_native_perform_op_delegate
  11. cib_native_set_connection_dnotify
  12. cib_native_register_notification

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

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