root/lib/cluster/legacy.c

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

DEFINITIONS

This source file includes following definitions.
  1. valid_cman_name
  2. plugin_get_details
  3. send_plugin_text
  4. terminate_cs_connection
  5. plugin_handle_membership
  6. plugin_default_deliver_message
  7. plugin_dispatch
  8. plugin_destroy
  9. pcmk_cman_dispatch
  10. cman_event_callback
  11. init_cman_connection
  12. cluster_connect_quorum
  13. init_cs_connection_classic
  14. pcmk_mcp_dispatch
  15. pcmk_mcp_destroy
  16. init_cs_connection
  17. classic_node_name
  18. cman_node_name
  19. init_cs_connection_once
  20. check_message_sanity
  21. get_config_opt
  22. config_find_init
  23. config_find_next
  24. find_corosync_variant
  25. crm_is_corosync_peer_active

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   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 <crm/cluster/internal.h>
  21 #include <bzlib.h>
  22 #include <crm/common/ipc.h>
  23 #include <crm/cluster.h>
  24 #include <crm/common/mainloop.h>
  25 #include <sys/utsname.h>
  26 #include <sys/socket.h>
  27 #include <netdb.h>
  28 
  29 #if SUPPORT_COROSYNC
  30 #  include <corosync/confdb.h>
  31 #  include <corosync/corodefs.h>
  32 #  include <corosync/cpg.h>
  33 #  include <corosync/cfg.h>
  34 #endif
  35 
  36 #if HAVE_CMAP
  37 #  include <corosync/cmap.h>
  38 #endif
  39 
  40 #if SUPPORT_CMAN
  41 #  include <libcman.h>
  42 cman_handle_t pcmk_cman_handle = NULL;
  43 #endif
  44 
  45 int ais_membership_timer = 0;
  46 gboolean ais_membership_force = FALSE;
  47 int plugin_dispatch(gpointer user_data);
  48 
  49 int ais_fd_sync = -1;
  50 int ais_fd_async = -1;          /* never send messages via this channel */
  51 void *ais_ipc_ctx = NULL;
  52 
  53 hdb_handle_t ais_ipc_handle = 0;
  54 
  55 #if SUPPORT_CMAN
  56 static bool valid_cman_name(const char *name, uint32_t nodeid) 
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58     bool rc = TRUE;
  59 
  60     /* Yes, %d, because that's what CMAN does */
  61     char *fakename = crm_strdup_printf("Node%d", nodeid);
  62 
  63     if(crm_str_eq(fakename, name, TRUE)) {
  64         rc = FALSE;
  65         crm_notice("Ignoring inferred name from cman: %s", fakename);
  66     }
  67     free(fakename);
  68     return rc;
  69 }
  70 #endif
  71 
  72 static gboolean
  73 plugin_get_details(uint32_t * id, char **uname)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75     struct iovec iov;
  76     int retries = 0;
  77     int rc = CS_OK;
  78     cs_ipc_header_response_t header;
  79     struct crm_ais_nodeid_resp_s answer;
  80 
  81     static uint32_t local_id = 0;
  82     static char *local_uname = NULL;
  83 
  84     if(local_id) {
  85         if(id) *id = local_id;
  86         if(uname) *uname = strdup(local_uname);
  87         return TRUE;
  88     }
  89 
  90     header.error = CS_OK;
  91     header.id = crm_class_nodeid;
  92     header.size = sizeof(cs_ipc_header_response_t);
  93 
  94     iov.iov_base = &header;
  95     iov.iov_len = header.size;
  96 
  97   retry:
  98     errno = 0;
  99     rc = coroipcc_msg_send_reply_receive(ais_ipc_handle, &iov, 1, &answer, sizeof(answer));
 100     if (rc == CS_OK) {
 101         CRM_CHECK(answer.header.size == sizeof(struct crm_ais_nodeid_resp_s),
 102                   crm_err("Odd message: id=%d, size=%d, error=%d",
 103                           answer.header.id, answer.header.size, answer.header.error));
 104         CRM_CHECK(answer.header.id == crm_class_nodeid,
 105                   crm_err("Bad response id: %d", answer.header.id));
 106     }
 107 
 108     if ((rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) && retries < 20) {
 109         retries++;
 110         crm_info("Peer overloaded: Re-sending message (Attempt %d of 20)", retries);
 111         sleep(retries);         /* Proportional back off */
 112         goto retry;
 113     }
 114 
 115     if (rc != CS_OK) {
 116         crm_err("Sending nodeid request: FAILED (rc=%d): %s", rc, ais_error2text(rc));
 117         return FALSE;
 118 
 119     } else if (answer.header.error != CS_OK) {
 120         crm_err("Bad response from peer: (rc=%d): %s", rc, ais_error2text(rc));
 121         return FALSE;
 122     }
 123 
 124     crm_info("Server details: id=%u uname=%s cname=%s", answer.id, answer.uname, answer.cname);
 125 
 126     local_id = answer.id;
 127     local_uname = strdup(answer.uname);
 128 
 129     if(id) *id = local_id;
 130     if(uname) *uname = strdup(local_uname);
 131     return TRUE;
 132 }
 133 
 134 bool
 135 send_plugin_text(int class, struct iovec *iov)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137     int rc = CS_OK;
 138     int retries = 0;
 139     int buf_len = sizeof(cs_ipc_header_response_t);
 140     char *buf = malloc(buf_len);
 141     AIS_Message *ais_msg = (AIS_Message*)iov[0].iov_base;
 142     cs_ipc_header_response_t *header = (cs_ipc_header_response_t *)(void*)buf;
 143 
 144     CRM_ASSERT(buf != NULL);
 145     /* There are only 6 handlers registered to crm_lib_service in plugin.c */
 146     CRM_CHECK(class < 6, crm_err("Invalid message class: %d", class);
 147               return FALSE);
 148 
 149     do {
 150         if (rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {
 151             retries++;
 152             crm_info("Peer overloaded or membership in flux:"
 153                      " Re-sending message (Attempt %d of 20)", retries);
 154             sleep(retries);     /* Proportional back off */
 155         }
 156 
 157         errno = 0;
 158         rc = coroipcc_msg_send_reply_receive(ais_ipc_handle, iov, 1, buf, buf_len);
 159 
 160     } while ((rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) && retries < 20);
 161 
 162     if (rc == CS_OK) {
 163         CRM_CHECK(header->size == sizeof(cs_ipc_header_response_t),
 164                   crm_err("Odd message: id=%d, size=%d, class=%d, error=%d",
 165                           header->id, header->size, class, header->error));
 166 
 167         CRM_ASSERT(buf_len >= header->size);
 168         CRM_CHECK(header->id == CRM_MESSAGE_IPC_ACK,
 169                   crm_err("Bad response id (%d) for request (%d)", header->id,
 170                           ais_msg->header.id));
 171         CRM_CHECK(header->error == CS_OK, rc = header->error);
 172 
 173     } else {
 174         crm_perror(LOG_ERR, "Sending plugin message %d FAILED: %s (%d)",
 175                    ais_msg->id, ais_error2text(rc), rc);
 176     }
 177 
 178     free(iov[0].iov_base);
 179     free(iov);
 180     free(buf);
 181 
 182     return (rc == CS_OK);
 183 }
 184 
 185 void
 186 terminate_cs_connection(crm_cluster_t *cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188     crm_info("Disconnecting from Corosync");
 189 
 190     if (is_classic_ais_cluster()) {
 191         if (ais_ipc_handle) {
 192             crm_trace("Disconnecting plugin");
 193             coroipcc_service_disconnect(ais_ipc_handle);
 194             ais_ipc_handle = 0;
 195         } else {
 196             crm_info("No plugin connection");
 197         }
 198     }
 199     cluster_disconnect_cpg(cluster);
 200 
 201 #  if SUPPORT_CMAN
 202     if (is_cman_cluster()) {
 203         if (pcmk_cman_handle) {
 204             crm_info("Disconnecting cman");
 205             if (cman_stop_notification(pcmk_cman_handle) >= 0) {
 206                 crm_info("Destroying cman");
 207                 cman_finish(pcmk_cman_handle);
 208             }
 209 
 210         } else {
 211             crm_info("No cman connection");
 212         }
 213     }
 214 #  endif
 215     ais_fd_async = -1;
 216     ais_fd_sync = -1;
 217 
 218     crm_notice("Disconnected from Corosync");
 219 }
 220 
 221 void
 222 plugin_handle_membership(AIS_Message *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224     if (msg->header.id == crm_class_members || msg->header.id == crm_class_quorum) {
 225         xmlNode *member = NULL;
 226         const char *value = NULL;
 227         gboolean quorate = FALSE;
 228         xmlNode *xml = string2xml(msg->data);
 229 
 230         if (xml == NULL) {
 231             crm_err("Invalid membership update: %s", msg->data);
 232             return;
 233         }
 234 
 235         value = crm_element_value(xml, "quorate");
 236         CRM_CHECK(value != NULL, crm_log_xml_err(xml, "No quorum value:"); return);
 237         if (crm_is_true(value)) {
 238             quorate = TRUE;
 239         }
 240 
 241         value = crm_element_value(xml, "id");
 242         CRM_CHECK(value != NULL, crm_log_xml_err(xml, "No membership id"); return);
 243         crm_peer_seq = crm_int_helper(value, NULL);
 244 
 245         if (quorate != crm_have_quorum) {
 246             crm_notice("Membership %s: quorum %s", value, quorate ? "acquired" : "lost");
 247             crm_have_quorum = quorate;
 248 
 249         } else {
 250             crm_info("Membership %s: quorum %s", value, quorate ? "retained" : "still lost");
 251         }
 252 
 253         for (member = __xml_first_child(xml); member != NULL; member = __xml_next(member)) {
 254             const char *id_s = crm_element_value(member, "id");
 255             const char *addr = crm_element_value(member, "addr");
 256             const char *uname = crm_element_value(member, "uname");
 257             const char *state = crm_element_value(member, "state");
 258             const char *born_s = crm_element_value(member, "born");
 259             const char *seen_s = crm_element_value(member, "seen");
 260             const char *votes_s = crm_element_value(member, "votes");
 261             const char *procs_s = crm_element_value(member, "processes");
 262 
 263             int votes = crm_int_helper(votes_s, NULL);
 264             unsigned int id = crm_int_helper(id_s, NULL);
 265             unsigned int procs = crm_int_helper(procs_s, NULL);
 266 
 267             /* TODO: These values will contain garbage if version < 0.7.1 */
 268             uint64_t born = crm_int_helper(born_s, NULL);
 269             uint64_t seen = crm_int_helper(seen_s, NULL);
 270 
 271             crm_update_peer(__FUNCTION__, id, born, seen, votes, procs, uname, uname, addr, state);
 272         }
 273         free_xml(xml);
 274     }
 275 }
 276 
 277 static void
 278 plugin_default_deliver_message(cpg_handle_t handle,
     /* [previous][next][first][last][top][bottom][index][help] */
 279                                const struct cpg_name *groupName,
 280                                uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 281 {
 282     uint32_t kind = 0;
 283     const char *from = NULL;
 284     char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
 285 
 286     free(data);
 287 }
 288 
 289 int
 290 plugin_dispatch(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292     int rc = CS_OK;
 293     crm_cluster_t *cluster = (crm_cluster_t *) user_data;
 294 
 295     do {
 296         char *buffer = NULL;
 297 
 298         rc = coroipcc_dispatch_get(ais_ipc_handle, (void **)&buffer, 0);
 299         if (rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {
 300             return 0;
 301         }
 302         if (rc != CS_OK) {
 303             crm_perror(LOG_ERR, "Receiving message body failed: (%d) %s", rc, ais_error2text(rc));
 304             return -1;
 305         }
 306         if (buffer == NULL) {
 307             /* NULL is a legal "no message afterall" value */
 308             return 0;
 309         }
 310         /*
 311         cpg_deliver_fn_t(cpg_handle_t handle, const struct cpg_name *group_name,
 312                          uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len);
 313         */
 314         if (cluster && cluster->cpg.cpg_deliver_fn) {
 315             cluster->cpg.cpg_deliver_fn(0, NULL, 0, 0, buffer, 0);
 316 
 317         } else {
 318             plugin_default_deliver_message(0, NULL, 0, 0, buffer, 0);
 319         }
 320 
 321         coroipcc_dispatch_put(ais_ipc_handle);
 322 
 323     } while (ais_ipc_handle);
 324 
 325     return 0;
 326 }
 327 
 328 static void
 329 plugin_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 330 {
 331     crm_err("AIS connection terminated");
 332     ais_fd_sync = -1;
 333     crm_exit(ENOTCONN);
 334 }
 335 
 336 #  if SUPPORT_CMAN
 337 
 338 static int
 339 pcmk_cman_dispatch(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 340 {
 341     int rc = cman_dispatch(pcmk_cman_handle, CMAN_DISPATCH_ALL);
 342 
 343     if (rc < 0) {
 344         crm_err("Connection to cman failed: %d", rc);
 345         pcmk_cman_handle = 0;
 346         return FALSE;
 347     }
 348     return TRUE;
 349 }
 350 
 351 #    define MAX_NODES 256
 352 
 353 static void
 354 cman_event_callback(cman_handle_t handle, void *privdata, int reason, int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 355 {
 356     int rc = 0, lpc = 0, node_count = 0;
 357 
 358     cman_cluster_t cluster;
 359     static cman_node_t cman_nodes[MAX_NODES];
 360 
 361     gboolean(*dispatch) (unsigned long long, gboolean) = privdata;
 362 
 363     switch (reason) {
 364         case CMAN_REASON_STATECHANGE:
 365 
 366             memset(&cluster, 0, sizeof(cluster));
 367             rc = cman_get_cluster(pcmk_cman_handle, &cluster);
 368             if (rc < 0) {
 369                 crm_err("Couldn't query cman cluster details: %d %d", rc, errno);
 370                 return;
 371             }
 372 
 373             crm_peer_seq = cluster.ci_generation;
 374             if (arg != crm_have_quorum) {
 375                 crm_notice("Membership %llu: quorum %s", crm_peer_seq, arg ? "acquired" : "lost");
 376                 crm_have_quorum = arg;
 377 
 378             } else {
 379                 crm_info("Membership %llu: quorum %s", crm_peer_seq,
 380                          arg ? "retained" : "still lost");
 381             }
 382 
 383             memset(cman_nodes, 0, MAX_NODES * sizeof(cman_node_t));
 384             rc = cman_get_nodes(pcmk_cman_handle, MAX_NODES, &node_count, cman_nodes);
 385             if (rc < 0) {
 386                 crm_err("Couldn't query cman node list: %d %d", rc, errno);
 387                 return;
 388             }
 389 
 390             for (lpc = 0; lpc < node_count; lpc++) {
 391                 crm_node_t *peer = NULL;
 392                 const char *name = NULL;
 393 
 394                 if (cman_nodes[lpc].cn_nodeid == 0) {
 395                     /* Never allow node ID 0 to be considered a member #315711 */
 396                     /* Skip entirely, it's a qdisk */
 397                     continue;
 398                 }
 399 
 400                 if(valid_cman_name(cman_nodes[lpc].cn_name, cman_nodes[lpc].cn_nodeid)) {
 401                     name = cman_nodes[lpc].cn_name;
 402                 }
 403 
 404                 peer = crm_get_peer(cman_nodes[lpc].cn_nodeid, name);
 405                 if(cman_nodes[lpc].cn_member) {
 406                     crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_MEMBER, crm_peer_seq);
 407 
 408                 } else if(peer->state) {
 409                     crm_update_peer_state(__FUNCTION__, peer, CRM_NODE_LOST, 0);
 410 
 411                 } else {
 412                     crm_info("State of node %s[%u] is still unknown", peer->uname, peer->id);
 413                 }
 414             }
 415 
 416             if (dispatch) {
 417                 dispatch(crm_peer_seq, crm_have_quorum);
 418             }
 419             break;
 420 
 421         case CMAN_REASON_TRY_SHUTDOWN:
 422             /* Always reply with a negative - pacemaker needs to be stopped first */
 423             crm_notice("CMAN wants to shut down: %s", arg ? "forced" : "optional");
 424             cman_replyto_shutdown(pcmk_cman_handle, 0);
 425             break;
 426 
 427         case CMAN_REASON_CONFIG_UPDATE:
 428             /* Ignore */
 429             break;
 430     }
 431 }
 432 #  endif
 433 
 434 gboolean
 435 init_cman_connection(gboolean(*dispatch) (unsigned long long, gboolean), void (*destroy) (gpointer))
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437 #  if SUPPORT_CMAN
 438     int rc = -1, fd = -1;
 439     cman_cluster_t cluster;
 440 
 441     struct mainloop_fd_callbacks cman_fd_callbacks = {
 442         .dispatch = pcmk_cman_dispatch,
 443         .destroy = destroy,
 444     };
 445 
 446     crm_info("Configuring Pacemaker to obtain quorum from cman");
 447 
 448     memset(&cluster, 0, sizeof(cluster));
 449 
 450     pcmk_cman_handle = cman_init(dispatch);
 451     if (pcmk_cman_handle == NULL || cman_is_active(pcmk_cman_handle) == FALSE) {
 452         crm_err("Couldn't connect to cman");
 453         goto cman_bail;
 454     }
 455 
 456     rc = cman_start_notification(pcmk_cman_handle, cman_event_callback);
 457     if (rc < 0) {
 458         crm_err("Couldn't register for cman notifications: %d %d", rc, errno);
 459         goto cman_bail;
 460     }
 461 
 462     /* Get the current membership state */
 463     cman_event_callback(pcmk_cman_handle, dispatch, CMAN_REASON_STATECHANGE,
 464                         cman_is_quorate(pcmk_cman_handle));
 465 
 466     fd = cman_get_fd(pcmk_cman_handle);
 467 
 468     mainloop_add_fd("cman", G_PRIORITY_MEDIUM, fd, dispatch, &cman_fd_callbacks);
 469 
 470   cman_bail:
 471     if (rc < 0) {
 472         cman_finish(pcmk_cman_handle);
 473         return FALSE;
 474     }
 475 #  else
 476     crm_err("cman qorum is not supported in this build");
 477     crm_exit(DAEMON_RESPAWN_STOP);
 478 #  endif
 479     return TRUE;
 480 }
 481 
 482 #  ifdef SUPPORT_COROSYNC
 483 
 484 gboolean
 485 cluster_connect_quorum(gboolean(*dispatch) (unsigned long long, gboolean),
     /* [previous][next][first][last][top][bottom][index][help] */
 486                        void (*destroy) (gpointer))
 487 {
 488     crm_err("The Corosync quorum API is not supported in this build");
 489     crm_exit(DAEMON_RESPAWN_STOP);
 490     return TRUE;
 491 }
 492 
 493 static gboolean
 494 init_cs_connection_classic(crm_cluster_t * cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 495 {
 496     int rc;
 497     int pid = 0;
 498     char *pid_s = NULL;
 499     const char *name = NULL;
 500     crm_node_t *peer = NULL;
 501     enum crm_proc_flag proc = 0;
 502 
 503     struct mainloop_fd_callbacks ais_fd_callbacks = {
 504         .dispatch = plugin_dispatch,
 505         .destroy = cluster->destroy,
 506     };
 507 
 508     crm_info("Creating connection to our Corosync plugin");
 509     rc = coroipcc_service_connect(COROSYNC_SOCKET_NAME, PCMK_SERVICE_ID,
 510                                   AIS_IPC_MESSAGE_SIZE, AIS_IPC_MESSAGE_SIZE, AIS_IPC_MESSAGE_SIZE,
 511                                   &ais_ipc_handle);
 512     if (ais_ipc_handle) {
 513         coroipcc_fd_get(ais_ipc_handle, &ais_fd_async);
 514     } else {
 515         crm_info("Connection to our Corosync plugin (%d) failed: %s (%d)",
 516                  PCMK_SERVICE_ID, strerror(errno), errno);
 517         return FALSE;
 518     }
 519     if (ais_fd_async <= 0 && rc == CS_OK) {
 520         crm_err("No context created, but connection reported 'ok'");
 521         rc = CS_ERR_LIBRARY;
 522     }
 523     if (rc != CS_OK) {
 524         crm_info("Connection to our Corosync plugin (%d) failed: %s (%d)", PCMK_SERVICE_ID,
 525                  ais_error2text(rc), rc);
 526     }
 527 
 528     if (rc != CS_OK) {
 529         return FALSE;
 530     }
 531 
 532     if (ais_fd_callbacks.destroy == NULL) {
 533         ais_fd_callbacks.destroy = plugin_destroy;
 534     }
 535 
 536     mainloop_add_fd("corosync-plugin", G_PRIORITY_MEDIUM, ais_fd_async, cluster, &ais_fd_callbacks);
 537     crm_info("AIS connection established");
 538 
 539     pid = getpid();
 540     pid_s = crm_itoa(pid);
 541     send_cluster_text(crm_class_cluster, pid_s, TRUE, NULL, crm_msg_ais);
 542     free(pid_s);
 543 
 544     cluster->nodeid = get_local_nodeid(0);
 545 
 546     name = get_local_node_name();
 547     plugin_get_details(NULL, &(cluster->uname));
 548     if (safe_str_neq(name, cluster->uname)) {
 549         crm_crit("Node name mismatch!  Corosync supplied %s but our lookup returned %s",
 550                  cluster->uname, name);
 551         crm_notice
 552             ("Node name mismatches usually occur when assigned automatically by DHCP servers");
 553         crm_exit(ENOTUNIQ);
 554     }
 555 
 556     proc = text2proc(crm_system_name);
 557     peer = crm_get_peer(cluster->nodeid, cluster->uname);
 558     crm_update_peer_proc(__FUNCTION__, peer, proc|crm_proc_plugin, ONLINESTATUS);
 559 
 560     return TRUE;
 561 }
 562 
 563 static int
 564 pcmk_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566     xmlNode *msg = string2xml(buffer);
 567 
 568     if (msg && is_classic_ais_cluster()) {
 569         xmlNode *node = NULL;
 570 
 571         for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
 572             int id = 0;
 573             int children = 0;
 574             const char *uname = crm_element_value(node, "uname");
 575 
 576             crm_element_value_int(node, "id", &id);
 577             crm_element_value_int(node, "processes", &children);
 578             if (id == 0) {
 579                 crm_log_xml_err(msg, "Bad Update");
 580             } else {
 581                 crm_node_t *peer = crm_get_peer(id, uname);
 582 
 583                 crm_update_peer_proc(__FUNCTION__, peer, children, NULL);
 584             }
 585         }
 586     }
 587 
 588     free_xml(msg);
 589     return 0;
 590 }
 591 
 592 static void
 593 pcmk_mcp_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 594 {
 595     void (*callback) (gpointer data) = user_data;
 596 
 597     if (callback) {
 598         callback(NULL);
 599     }
 600 }
 601 
 602 gboolean
 603 init_cs_connection(crm_cluster_t * cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 604 {
 605     int retries = 0;
 606 
 607     static struct ipc_client_callbacks mcp_callbacks = {
 608         .dispatch = pcmk_mcp_dispatch,
 609         .destroy = pcmk_mcp_destroy
 610     };
 611 
 612     while (retries < 5) {
 613         int rc = init_cs_connection_once(cluster);
 614 
 615         retries++;
 616         switch (rc) {
 617             case CS_OK:
 618                 if (getenv("HA_mcp") && get_cluster_type() != pcmk_cluster_cman) {
 619                     xmlNode *poke = create_xml_node(NULL, "poke");
 620                     mainloop_io_t *ipc =
 621                         mainloop_add_ipc_client(CRM_SYSTEM_MCP, G_PRIORITY_MEDIUM, 0,
 622                                                 cluster->destroy, &mcp_callbacks);
 623 
 624                     crm_ipc_send(mainloop_get_ipc_client(ipc), poke, 0, 0, NULL);
 625                     free_xml(poke);
 626                 }
 627                 return TRUE;
 628                 break;
 629             case CS_ERR_TRY_AGAIN:
 630             case CS_ERR_QUEUE_FULL:
 631                 sleep(retries);
 632                 break;
 633             default:
 634                 return FALSE;
 635         }
 636     }
 637 
 638     crm_err("Retry count exceeded: %d", retries);
 639     return FALSE;
 640 }
 641 
 642 char *
 643 classic_node_name(uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 644 {
 645     return NULL;                /* Always use the uname() default for localhost.  No way to look up peers */
 646 }
 647 
 648 char *
 649 cman_node_name(uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 650 {
 651     char *name = NULL;
 652 
 653 #  if SUPPORT_CMAN
 654     cman_node_t us;
 655     cman_handle_t cman;
 656 
 657     cman = cman_init(NULL);
 658     if (cman != NULL && cman_is_active(cman)) {
 659 
 660         memset(&us, 0, sizeof(cman_node_t));
 661         cman_get_node(cman, nodeid, &us);
 662         if(valid_cman_name(us.cn_name, nodeid)) {
 663             name = strdup(us.cn_name);
 664             crm_info("Using CMAN node name %s for %u", name, nodeid);
 665         }
 666      }
 667 
 668     cman_finish(cman);
 669 #  endif
 670     if (name == NULL) {
 671         crm_debug("Unable to get node name for nodeid %u", nodeid);
 672     }
 673     return name;
 674 }
 675 
 676 extern int set_cluster_type(enum cluster_type_e type);
 677 
 678 gboolean
 679 init_cs_connection_once(crm_cluster_t * cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
 680 {
 681     crm_node_t *peer = NULL;
 682     enum cluster_type_e stack = get_cluster_type();
 683 
 684     crm_peer_init();
 685 
 686     /* Here we just initialize comms */
 687     switch (stack) {
 688         case pcmk_cluster_classic_ais:
 689             if (init_cs_connection_classic(cluster) == FALSE) {
 690                 return FALSE;
 691             }
 692             break;
 693         case pcmk_cluster_cman:
 694             if (cluster_connect_cpg(cluster) == FALSE) {
 695                 return FALSE;
 696             }
 697             break;
 698         case pcmk_cluster_heartbeat:
 699             crm_info("Could not find an active corosync based cluster");
 700             return FALSE;
 701             break;
 702         default:
 703             crm_err("Invalid cluster type: %s (%d)", name_for_cluster_type(stack), stack);
 704             return FALSE;
 705             break;
 706     }
 707 
 708     crm_info("Connection to '%s': established", name_for_cluster_type(stack));
 709 
 710     cluster->nodeid = get_local_nodeid(0);
 711     if(cluster->nodeid == 0) {
 712         crm_err("Could not establish local nodeid");
 713         return FALSE;
 714     }
 715 
 716     cluster->uname = get_node_name(0);
 717     if(cluster->uname == NULL) {
 718         crm_err("Could not establish local node name");
 719         return FALSE;
 720     }
 721 
 722     /* Ensure the local node always exists */
 723     peer = crm_get_peer(cluster->nodeid, cluster->uname);
 724     cluster->uuid = get_corosync_uuid(peer);
 725 
 726     return TRUE;
 727 }
 728 
 729 gboolean
 730 check_message_sanity(const AIS_Message * msg, const char *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 731 {
 732     gboolean sane = TRUE;
 733     int dest = msg->host.type;
 734     int tmp_size = msg->header.size - sizeof(AIS_Message);
 735 
 736     if (sane && msg->header.size == 0) {
 737         crm_warn("Message with no size");
 738         sane = FALSE;
 739     }
 740 
 741     if (sane && msg->header.error != CS_OK) {
 742         crm_warn("Message header contains an error: %d", msg->header.error);
 743         sane = FALSE;
 744     }
 745 
 746     if (sane && ais_data_len(msg) != tmp_size) {
 747         crm_warn("Message payload size is incorrect: expected %d, got %d", ais_data_len(msg),
 748                  tmp_size);
 749         sane = TRUE;
 750     }
 751 
 752     if (sane && ais_data_len(msg) == 0) {
 753         crm_warn("Message with no payload");
 754         sane = FALSE;
 755     }
 756 
 757     if (sane && data && msg->is_compressed == FALSE) {
 758         int str_size = strlen(data) + 1;
 759 
 760         if (ais_data_len(msg) != str_size) {
 761             int lpc = 0;
 762 
 763             crm_warn("Message payload is corrupted: expected %d bytes, got %d",
 764                      ais_data_len(msg), str_size);
 765             sane = FALSE;
 766             for (lpc = (str_size - 10); lpc < msg->size; lpc++) {
 767                 if (lpc < 0) {
 768                     lpc = 0;
 769                 }
 770                 crm_debug("bad_data[%d]: %d / '%c'", lpc, data[lpc], data[lpc]);
 771             }
 772         }
 773     }
 774 
 775     if (sane == FALSE) {
 776         crm_err("Invalid message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
 777                 msg->id, ais_dest(&(msg->host)), msg_type2text(dest),
 778                 ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
 779                 msg->sender.pid, msg->is_compressed, ais_data_len(msg), msg->header.size);
 780 
 781     } else {
 782         crm_trace
 783             ("Verified message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
 784              msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)),
 785              msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed,
 786              ais_data_len(msg), msg->header.size);
 787     }
 788 
 789     return sane;
 790 }
 791 #endif
 792 
 793 static int
 794 get_config_opt(confdb_handle_t config,
     /* [previous][next][first][last][top][bottom][index][help] */
 795                hdb_handle_t object_handle, const char *key, char **value, const char *fallback)
 796 {
 797     size_t len = 0;
 798     char *env_key = NULL;
 799     const char *env_value = NULL;
 800     char buffer[256];
 801 
 802     if (*value) {
 803         free(*value);
 804         *value = NULL;
 805     }
 806 
 807     if (object_handle > 0) {
 808         if (CS_OK == confdb_key_get(config, object_handle, key, strlen(key), &buffer, &len)) {
 809             *value = strdup(buffer);
 810         }
 811     }
 812 
 813     if (*value) {
 814         crm_info("Found '%s' for option: %s", *value, key);
 815         return 0;
 816     }
 817 
 818     env_key = crm_concat("HA", key, '_');
 819     env_value = getenv(env_key);
 820     free(env_key);
 821 
 822     if (*value) {
 823         crm_info("Found '%s' in ENV for option: %s", *value, key);
 824         *value = strdup(env_value);
 825         return 0;
 826     }
 827 
 828     if (fallback) {
 829         crm_info("Defaulting to '%s' for option: %s", fallback, key);
 830         *value = strdup(fallback);
 831 
 832     } else {
 833         crm_info("No default for option: %s", key);
 834     }
 835 
 836     return -1;
 837 }
 838 
 839 static confdb_handle_t
 840 config_find_init(confdb_handle_t config)
     /* [previous][next][first][last][top][bottom][index][help] */
 841 {
 842     cs_error_t rc = CS_OK;
 843     confdb_handle_t local_handle = OBJECT_PARENT_HANDLE;
 844 
 845     rc = confdb_object_find_start(config, local_handle);
 846     if (rc == CS_OK) {
 847         return local_handle;
 848     } else {
 849         crm_err("Couldn't create search context: %d", rc);
 850     }
 851     return 0;
 852 }
 853 
 854 static hdb_handle_t
 855 config_find_next(confdb_handle_t config, const char *name, confdb_handle_t top_handle)
     /* [previous][next][first][last][top][bottom][index][help] */
 856 {
 857     cs_error_t rc = CS_OK;
 858     hdb_handle_t local_handle = 0;
 859 
 860     if (top_handle == 0) {
 861         crm_err("Couldn't search for %s: no valid context", name);
 862         return 0;
 863     }
 864 
 865     crm_trace("Searching for %s in " HDB_X_FORMAT, name, top_handle);
 866     rc = confdb_object_find(config, top_handle, name, strlen(name), &local_handle);
 867     if (rc != CS_OK) {
 868         crm_info("No additional configuration supplied for: %s", name);
 869         local_handle = 0;
 870     } else {
 871         crm_info("Processing additional %s options...", name);
 872     }
 873     return local_handle;
 874 }
 875 
 876 enum cluster_type_e
 877 find_corosync_variant(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 878 {
 879     confdb_handle_t config;
 880     enum cluster_type_e found = pcmk_cluster_unknown;
 881 
 882     int rc;
 883     char *value = NULL;
 884     confdb_handle_t top_handle = 0;
 885     hdb_handle_t local_handle = 0;
 886     static confdb_callbacks_t callbacks = { };
 887 
 888     rc = confdb_initialize(&config, &callbacks);
 889     if (rc != CS_OK) {
 890         crm_debug("Could not initialize Cluster Configuration Database API instance error %d", rc);
 891         return found;
 892     }
 893 
 894     top_handle = config_find_init(config);
 895     local_handle = config_find_next(config, "service", top_handle);
 896     while (local_handle) {
 897         get_config_opt(config, local_handle, "name", &value, NULL);
 898         if (safe_str_eq("pacemaker", value)) {
 899             found = pcmk_cluster_classic_ais;
 900 
 901             get_config_opt(config, local_handle, "ver", &value, "0");
 902             crm_trace("Found Pacemaker plugin version: %s", value);
 903             break;
 904         }
 905 
 906         local_handle = config_find_next(config, "service", top_handle);
 907     }
 908 
 909     if (found == pcmk_cluster_unknown) {
 910         top_handle = config_find_init(config);
 911         local_handle = config_find_next(config, "quorum", top_handle);
 912         get_config_opt(config, local_handle, "provider", &value, NULL);
 913 
 914         if (safe_str_eq("quorum_cman", value)) {
 915             crm_trace("Found CMAN quorum provider");
 916             found = pcmk_cluster_cman;
 917         }
 918     }
 919     free(value);
 920 
 921     confdb_finalize(config);
 922     if (found == pcmk_cluster_unknown) {
 923         crm_err
 924             ("Corosync is running, but Pacemaker could not find the CMAN or Pacemaker plugin loaded");
 925         found = pcmk_cluster_invalid;
 926     }
 927     return found;
 928 }
 929 
 930 gboolean
 931 crm_is_corosync_peer_active(const crm_node_t * node)
     /* [previous][next][first][last][top][bottom][index][help] */
 932 {
 933     enum crm_proc_flag proc = crm_proc_none;
 934 
 935     if (node == NULL) {
 936         crm_trace("NULL");
 937         return FALSE;
 938 
 939     } else if (safe_str_neq(node->state, CRM_NODE_MEMBER)) {
 940         crm_trace("%s: state=%s", node->uname, node->state);
 941         return FALSE;
 942 
 943     } else if (is_cman_cluster() && (node->processes & crm_proc_cpg)) {
 944         /* If we can still talk to our peer process on that node,
 945          * then it's also part of the corosync membership
 946          */
 947         crm_trace("%s: processes=%.8x", node->uname, node->processes);
 948         return TRUE;
 949 
 950     } else if (is_classic_ais_cluster()) {
 951         if (node->processes < crm_proc_none) {
 952             crm_debug("%s: unknown process list, assuming active for now", node->uname);
 953             return TRUE;
 954 
 955         } else if (is_set(node->processes, crm_proc_none)) {
 956             crm_debug("%s: all processes are inactive", node->uname);
 957             return FALSE;
 958 
 959         } else if (is_not_set(node->processes, crm_proc_plugin)) {
 960             crm_trace("%s: processes=%.8x", node->uname, node->processes);
 961             return FALSE;
 962         }
 963     }
 964 
 965     proc = text2proc(crm_system_name);
 966     if (proc > crm_proc_none && (node->processes & proc) == 0) {
 967         crm_trace("%s: proc %.8x not in %.8x", node->uname, proc, node->processes);
 968         return FALSE;
 969     }
 970 
 971     return TRUE;
 972 }

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