root/crmd/messages.c

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

DEFINITIONS

This source file includes following definitions.
  1. register_fsa_error_adv
  2. register_fsa_input_adv
  3. fsa_dump_queue
  4. copy_ha_msg_input
  5. delete_fsa_input
  6. get_message
  7. is_message
  8. fsa_typed_data_adv
  9. do_msg_route
  10. route_message
  11. relay_message
  12. process_hello_message
  13. crmd_authorize_message
  14. handle_message
  15. handle_failcount_op
  16. handle_remote_state
  17. handle_request
  18. handle_response
  19. handle_shutdown_request
  20. send_msg_via_ipc
  21. new_ha_msg_input
  22. delete_ha_msg_input
  23. send_remote_state_message

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This software 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  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU 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 
  21 #include <sys/param.h>
  22 #include <crm/crm.h>
  23 #include <string.h>
  24 #include <time.h>
  25 #include <crmd_fsa.h>
  26 
  27 #include <crm/msg_xml.h>
  28 #include <crm/common/xml.h>
  29 
  30 #include <crm/cluster/internal.h>
  31 #include <crm/cib.h>
  32 #include <crm/common/ipcs.h>
  33 
  34 #include <crmd.h>
  35 #include <crmd_messages.h>
  36 #include <crmd_lrm.h>
  37 #include <tengine.h>
  38 #include <throttle.h>
  39 
  40 GListPtr fsa_message_queue = NULL;
  41 extern void crm_shutdown(int nsig);
  42 
  43 extern crm_ipc_t *attrd_ipc;
  44 void handle_response(xmlNode * stored_msg);
  45 enum crmd_fsa_input handle_request(xmlNode * stored_msg, enum crmd_fsa_cause cause);
  46 enum crmd_fsa_input handle_shutdown_request(xmlNode * stored_msg);
  47 
  48 #define ROUTER_RESULT(x)        crm_trace("Router result: %s", x)
  49 
  50 /* debug only, can wrap all it likes */
  51 int last_data_id = 0;
  52 
  53 void
  54 register_fsa_error_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
     /* [previous][next][first][last][top][bottom][index][help] */
  55                        fsa_data_t * cur_data, void *new_data, const char *raised_from)
  56 {
  57     /* save the current actions if any */
  58     if (fsa_actions != A_NOTHING) {
  59         register_fsa_input_adv(cur_data ? cur_data->fsa_cause : C_FSA_INTERNAL,
  60                                I_NULL, cur_data ? cur_data->data : NULL,
  61                                fsa_actions, TRUE, __FUNCTION__);
  62     }
  63 
  64     /* reset the action list */
  65     crm_info("Resetting the current action list");
  66     fsa_dump_actions(fsa_actions, "Drop");
  67     fsa_actions = A_NOTHING;
  68 
  69     /* register the error */
  70     register_fsa_input_adv(cause, input, new_data, A_NOTHING, TRUE, raised_from);
  71 }
  72 
  73 int
  74 register_fsa_input_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
     /* [previous][next][first][last][top][bottom][index][help] */
  75                        void *data, long long with_actions,
  76                        gboolean prepend, const char *raised_from)
  77 {
  78     unsigned old_len = g_list_length(fsa_message_queue);
  79     fsa_data_t *fsa_data = NULL;
  80 
  81     CRM_CHECK(raised_from != NULL, raised_from = "<unknown>");
  82 
  83     if (input == I_NULL && with_actions == A_NOTHING /* && data == NULL */ ) {
  84         /* no point doing anything */
  85         crm_err("Cannot add entry to queue: no input and no action");
  86         return 0;
  87     }
  88 
  89     if (input == I_WAIT_FOR_EVENT) {
  90         do_fsa_stall = TRUE;
  91         crm_debug("Stalling the FSA pending further input: source=%s cause=%s data=%p queue=%d",
  92                   raised_from, fsa_cause2string(cause), data, old_len);
  93 
  94         if (old_len > 0) {
  95             fsa_dump_queue(LOG_TRACE);
  96             prepend = FALSE;
  97         }
  98 
  99         if (data == NULL) {
 100             fsa_actions |= with_actions;
 101             fsa_dump_actions(with_actions, "Restored");
 102             return 0;
 103         }
 104 
 105         /* Store everything in the new event and reset fsa_actions */
 106         with_actions |= fsa_actions;
 107         fsa_actions = A_NOTHING;
 108     }
 109 
 110     last_data_id++;
 111     crm_trace("%s %s FSA input %d (%s) (cause=%s) %s data",
 112               raised_from, prepend ? "prepended" : "appended", last_data_id,
 113               fsa_input2string(input), fsa_cause2string(cause), data ? "with" : "without");
 114 
 115     fsa_data = calloc(1, sizeof(fsa_data_t));
 116     fsa_data->id = last_data_id;
 117     fsa_data->fsa_input = input;
 118     fsa_data->fsa_cause = cause;
 119     fsa_data->origin = raised_from;
 120     fsa_data->data = NULL;
 121     fsa_data->data_type = fsa_dt_none;
 122     fsa_data->actions = with_actions;
 123 
 124     if (with_actions != A_NOTHING) {
 125         crm_trace("Adding actions %.16llx to input", with_actions);
 126     }
 127 
 128     if (data != NULL) {
 129         switch (cause) {
 130             case C_FSA_INTERNAL:
 131             case C_CRMD_STATUS_CALLBACK:
 132             case C_IPC_MESSAGE:
 133             case C_HA_MESSAGE:
 134                 crm_trace("Copying %s data from %s as a HA msg",
 135                           fsa_cause2string(cause), raised_from);
 136                 CRM_CHECK(((ha_msg_input_t *) data)->msg != NULL,
 137                           crm_err("Bogus data from %s", raised_from));
 138                 fsa_data->data = copy_ha_msg_input(data);
 139                 fsa_data->data_type = fsa_dt_ha_msg;
 140                 break;
 141 
 142             case C_LRM_OP_CALLBACK:
 143                 crm_trace("Copying %s data from %s as lrmd_event_data_t",
 144                           fsa_cause2string(cause), raised_from);
 145                 fsa_data->data = lrmd_copy_event((lrmd_event_data_t *) data);
 146                 fsa_data->data_type = fsa_dt_lrm;
 147                 break;
 148 
 149             case C_CCM_CALLBACK:
 150             case C_SUBSYSTEM_CONNECT:
 151             case C_LRM_MONITOR_CALLBACK:
 152             case C_TIMER_POPPED:
 153             case C_SHUTDOWN:
 154             case C_HEARTBEAT_FAILED:
 155             case C_HA_DISCONNECT:
 156             case C_ILLEGAL:
 157             case C_UNKNOWN:
 158             case C_STARTUP:
 159                 crm_err("Copying %s data (from %s)"
 160                         " not yet implemented", fsa_cause2string(cause), raised_from);
 161                 crmd_exit(pcmk_err_generic);
 162                 break;
 163         }
 164         crm_trace("%s data copied", fsa_cause2string(fsa_data->fsa_cause));
 165     }
 166 
 167     /* make sure to free it properly later */
 168     if (prepend) {
 169         crm_trace("Prepending input");
 170         fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data);
 171     } else {
 172         fsa_message_queue = g_list_append(fsa_message_queue, fsa_data);
 173     }
 174 
 175     crm_trace("Queue len: %d", g_list_length(fsa_message_queue));
 176 
 177     /* fsa_dump_queue(LOG_DEBUG_2); */
 178 
 179     if (old_len == g_list_length(fsa_message_queue)) {
 180         crm_err("Couldn't add message to the queue");
 181     }
 182 
 183     if (fsa_source && input != I_WAIT_FOR_EVENT) {
 184         crm_trace("Triggering FSA: %s", __FUNCTION__);
 185         mainloop_set_trigger(fsa_source);
 186     }
 187     return last_data_id;
 188 }
 189 
 190 void
 191 fsa_dump_queue(int log_level)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193     int offset = 0;
 194     GListPtr lpc = NULL;
 195 
 196     for (lpc = fsa_message_queue; lpc != NULL; lpc = lpc->next) {
 197         fsa_data_t *data = (fsa_data_t *) lpc->data;
 198 
 199         do_crm_log_unlikely(log_level,
 200                             "queue[%d.%d]: input %s raised by %s(%p.%d)\t(cause=%s)",
 201                             offset++, data->id, fsa_input2string(data->fsa_input),
 202                             data->origin, data->data, data->data_type,
 203                             fsa_cause2string(data->fsa_cause));
 204     }
 205 }
 206 
 207 ha_msg_input_t *
 208 copy_ha_msg_input(ha_msg_input_t * orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210     ha_msg_input_t *copy = NULL;
 211     xmlNodePtr data = NULL;
 212 
 213     if (orig != NULL) {
 214         crm_trace("Copy msg");
 215         data = copy_xml(orig->msg);
 216 
 217     } else {
 218         crm_trace("No message to copy");
 219     }
 220     copy = new_ha_msg_input(data);
 221     if (orig && orig->msg != NULL) {
 222         CRM_CHECK(copy->msg != NULL, crm_err("copy failed"));
 223     }
 224     return copy;
 225 }
 226 
 227 void
 228 delete_fsa_input(fsa_data_t * fsa_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230     lrmd_event_data_t *op = NULL;
 231     xmlNode *foo = NULL;
 232 
 233     if (fsa_data == NULL) {
 234         return;
 235     }
 236     crm_trace("About to free %s data", fsa_cause2string(fsa_data->fsa_cause));
 237 
 238     if (fsa_data->data != NULL) {
 239         switch (fsa_data->data_type) {
 240             case fsa_dt_ha_msg:
 241                 delete_ha_msg_input(fsa_data->data);
 242                 break;
 243 
 244             case fsa_dt_xml:
 245                 foo = fsa_data->data;
 246                 free_xml(foo);
 247                 break;
 248 
 249             case fsa_dt_lrm:
 250                 op = (lrmd_event_data_t *) fsa_data->data;
 251                 lrmd_free_event(op);
 252                 break;
 253 
 254             case fsa_dt_none:
 255                 if (fsa_data->data != NULL) {
 256                     crm_err("Don't know how to free %s data from %s",
 257                             fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin);
 258                     crmd_exit(pcmk_err_generic);
 259                 }
 260                 break;
 261         }
 262         crm_trace("%s data freed", fsa_cause2string(fsa_data->fsa_cause));
 263     }
 264 
 265     free(fsa_data);
 266 }
 267 
 268 /* returns the next message */
 269 fsa_data_t *
 270 get_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272     fsa_data_t *message = g_list_nth_data(fsa_message_queue, 0);
 273 
 274     fsa_message_queue = g_list_remove(fsa_message_queue, message);
 275     crm_trace("Processing input %d", message->id);
 276     return message;
 277 }
 278 
 279 /* returns the current head of the FIFO queue */
 280 gboolean
 281 is_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283     return (g_list_length(fsa_message_queue) > 0);
 284 }
 285 
 286 void *
 287 fsa_typed_data_adv(fsa_data_t * fsa_data, enum fsa_data_type a_type, const char *caller)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289     void *ret_val = NULL;
 290 
 291     if (fsa_data == NULL) {
 292         crm_err("%s: No FSA data available", caller);
 293 
 294     } else if (fsa_data->data == NULL) {
 295         crm_err("%s: No message data available. Origin: %s", caller, fsa_data->origin);
 296 
 297     } else if (fsa_data->data_type != a_type) {
 298         crm_crit("%s: Message data was the wrong type! %d vs. requested=%d.  Origin: %s",
 299                  caller, fsa_data->data_type, a_type, fsa_data->origin);
 300         CRM_ASSERT(fsa_data->data_type == a_type);
 301     } else {
 302         ret_val = fsa_data->data;
 303     }
 304 
 305     return ret_val;
 306 }
 307 
 308 /*      A_MSG_ROUTE     */
 309 void
 310 do_msg_route(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 311              enum crmd_fsa_cause cause,
 312              enum crmd_fsa_state cur_state,
 313              enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 314 {
 315     ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
 316 
 317     route_message(msg_data->fsa_cause, input->msg);
 318 }
 319 
 320 void
 321 route_message(enum crmd_fsa_cause cause, xmlNode * input)
     /* [previous][next][first][last][top][bottom][index][help] */
 322 {
 323     ha_msg_input_t fsa_input;
 324     enum crmd_fsa_input result = I_NULL;
 325 
 326     fsa_input.msg = input;
 327     CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return);
 328 
 329     /* try passing the buck first */
 330     if (relay_message(input, cause == C_IPC_MESSAGE)) {
 331         return;
 332     }
 333 
 334     /* handle locally */
 335     result = handle_message(input, cause);
 336 
 337     /* done or process later? */
 338     switch (result) {
 339         case I_NULL:
 340         case I_CIB_OP:
 341         case I_ROUTER:
 342         case I_NODE_JOIN:
 343         case I_JOIN_REQUEST:
 344         case I_JOIN_RESULT:
 345             break;
 346         default:
 347             /* Defering local processing of message */
 348             register_fsa_input_later(cause, result, &fsa_input);
 349             return;
 350     }
 351 
 352     if (result != I_NULL) {
 353         /* add to the front of the queue */
 354         register_fsa_input(cause, result, &fsa_input);
 355     }
 356 }
 357 
 358 gboolean
 359 relay_message(xmlNode * msg, gboolean originated_locally)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 {
 361     int dest = 1;
 362     int is_for_dc = 0;
 363     int is_for_dcib = 0;
 364     int is_for_te = 0;
 365     int is_for_crm = 0;
 366     int is_for_cib = 0;
 367     int is_local = 0;
 368     gboolean processing_complete = FALSE;
 369     const char *host_to = crm_element_value(msg, F_CRM_HOST_TO);
 370     const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
 371     const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM);
 372     const char *type = crm_element_value(msg, F_TYPE);
 373     const char *msg_error = NULL;
 374 
 375     crm_trace("Routing message %s", crm_element_value(msg, XML_ATTR_REFERENCE));
 376 
 377     if (msg == NULL) {
 378         msg_error = "Cannot route empty message";
 379 
 380     } else if (safe_str_eq(CRM_OP_HELLO, crm_element_value(msg, F_CRM_TASK))) {
 381         /* quietly ignore */
 382         processing_complete = TRUE;
 383 
 384     } else if (safe_str_neq(type, T_CRM)) {
 385         msg_error = "Bad message type";
 386 
 387     } else if (sys_to == NULL) {
 388         msg_error = "Bad message destination: no subsystem";
 389     }
 390 
 391     if (msg_error != NULL) {
 392         processing_complete = TRUE;
 393         crm_err("%s", msg_error);
 394         crm_log_xml_warn(msg, "bad msg");
 395     }
 396 
 397     if (processing_complete) {
 398         return TRUE;
 399     }
 400 
 401     processing_complete = TRUE;
 402 
 403     is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
 404     is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
 405     is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
 406     is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
 407     is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);
 408 
 409     is_local = 0;
 410     if (host_to == NULL || strlen(host_to) == 0) {
 411         if (is_for_dc || is_for_te) {
 412             is_local = 0;
 413 
 414         } else if (is_for_crm && originated_locally) {
 415             is_local = 0;
 416 
 417         } else {
 418             is_local = 1;
 419         }
 420 
 421     } else if (safe_str_eq(fsa_our_uname, host_to)) {
 422         is_local = 1;
 423     }
 424 
 425     if (is_for_dc || is_for_dcib || is_for_te) {
 426         if (AM_I_DC && is_for_te) {
 427             ROUTER_RESULT("Message result: Local relay");
 428             send_msg_via_ipc(msg, sys_to);
 429 
 430         } else if (AM_I_DC) {
 431             ROUTER_RESULT("Message result: DC/CRMd process");
 432             processing_complete = FALSE;        /* more to be done by caller */
 433         } else if (originated_locally && safe_str_neq(sys_from, CRM_SYSTEM_PENGINE)
 434                    && safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) {
 435 
 436             /* Neither the TE or PE should be sending messages
 437              *   to DC's on other nodes
 438              *
 439              * By definition, if we are no longer the DC, then
 440              *   the PE or TE's data should be discarded
 441              */
 442 
 443 #if SUPPORT_COROSYNC
 444             if (is_openais_cluster()) {
 445                 dest = text2msg_type(sys_to);
 446             }
 447 #endif
 448             ROUTER_RESULT("Message result: External relay to DC");
 449             send_cluster_message(host_to ? crm_get_peer(0, host_to) : NULL, dest, msg, TRUE);
 450 
 451         } else {
 452             /* discard */
 453             ROUTER_RESULT("Message result: Discard, not DC");
 454         }
 455 
 456     } else if (is_local && (is_for_crm || is_for_cib)) {
 457         ROUTER_RESULT("Message result: CRMd process");
 458         processing_complete = FALSE;    /* more to be done by caller */
 459 
 460     } else if (is_local) {
 461         ROUTER_RESULT("Message result: Local relay");
 462         send_msg_via_ipc(msg, sys_to);
 463 
 464     } else {
 465         crm_node_t *node_to = NULL;
 466 
 467 #if SUPPORT_COROSYNC
 468         if (is_openais_cluster()) {
 469             dest = text2msg_type(sys_to);
 470 
 471             if (dest == crm_msg_none || dest > crm_msg_stonith_ng) {
 472                 dest = crm_msg_crmd;
 473             }
 474         }
 475 #endif
 476 
 477         if (host_to) {
 478             node_to = crm_find_peer(0, host_to);
 479             if (node_to == NULL) {
 480                crm_err("Cannot route message to unknown node %s", host_to);
 481                return TRUE;
 482             }
 483         }
 484 
 485         ROUTER_RESULT("Message result: External relay");
 486         send_cluster_message(host_to ? node_to : NULL, dest, msg, TRUE);
 487     }
 488 
 489     return processing_complete;
 490 }
 491 
 492 static gboolean
 493 process_hello_message(xmlNode * hello,
     /* [previous][next][first][last][top][bottom][index][help] */
 494                       char **client_name, char **major_version, char **minor_version)
 495 {
 496     const char *local_client_name;
 497     const char *local_major_version;
 498     const char *local_minor_version;
 499 
 500     *client_name = NULL;
 501     *major_version = NULL;
 502     *minor_version = NULL;
 503 
 504     if (hello == NULL) {
 505         return FALSE;
 506     }
 507 
 508     local_client_name = crm_element_value(hello, "client_name");
 509     local_major_version = crm_element_value(hello, "major_version");
 510     local_minor_version = crm_element_value(hello, "minor_version");
 511 
 512     if (local_client_name == NULL || strlen(local_client_name) == 0) {
 513         crm_err("Hello message was not valid (field %s not found)", "client name");
 514         return FALSE;
 515 
 516     } else if (local_major_version == NULL || strlen(local_major_version) == 0) {
 517         crm_err("Hello message was not valid (field %s not found)", "major version");
 518         return FALSE;
 519 
 520     } else if (local_minor_version == NULL || strlen(local_minor_version) == 0) {
 521         crm_err("Hello message was not valid (field %s not found)", "minor version");
 522         return FALSE;
 523     }
 524 
 525     *client_name = strdup(local_client_name);
 526     *major_version = strdup(local_major_version);
 527     *minor_version = strdup(local_minor_version);
 528 
 529     crm_trace("Hello message ok");
 530     return TRUE;
 531 }
 532 
 533 gboolean
 534 crmd_authorize_message(xmlNode * client_msg, crm_client_t * curr_client, const char *proxy_session)
     /* [previous][next][first][last][top][bottom][index][help] */
 535 {
 536     char *client_name = NULL;
 537     char *major_version = NULL;
 538     char *minor_version = NULL;
 539     gboolean auth_result = FALSE;
 540 
 541     xmlNode *xml = NULL;
 542     const char *op = crm_element_value(client_msg, F_CRM_TASK);
 543     const char *uuid = curr_client ? curr_client->id : proxy_session;
 544 
 545     if (uuid == NULL) {
 546         crm_warn("Message [%s] not authorized", crm_element_value(client_msg, XML_ATTR_REFERENCE));
 547         return FALSE;
 548 
 549     } else if (safe_str_neq(CRM_OP_HELLO, op)) {
 550         return TRUE;
 551     }
 552 
 553     xml = get_message_xml(client_msg, F_CRM_DATA);
 554     auth_result = process_hello_message(xml, &client_name, &major_version, &minor_version);
 555 
 556     if (auth_result == TRUE) {
 557         if (client_name == NULL) {
 558             crm_err("Bad client details (client_name=%s, uuid=%s)",
 559                     crm_str(client_name), uuid);
 560             auth_result = FALSE;
 561         }
 562     }
 563 
 564     if (auth_result == TRUE) {
 565         /* check version */
 566         int mav = atoi(major_version);
 567         int miv = atoi(minor_version);
 568 
 569         crm_trace("Checking client version number");
 570         if (mav < 0 || miv < 0) {
 571             crm_err("Client version (%d:%d) is not acceptable", mav, miv);
 572             auth_result = FALSE;
 573         }
 574     }
 575 
 576     if (auth_result == TRUE) {
 577         crm_trace("Accepted client %s", client_name);
 578         if (curr_client) {
 579             curr_client->userdata = strdup(client_name);
 580         }
 581 
 582         crm_trace("Triggering FSA: %s", __FUNCTION__);
 583         mainloop_set_trigger(fsa_source);
 584 
 585     } else {
 586         crm_warn("Rejected client logon request");
 587         if (curr_client) {
 588             qb_ipcs_disconnect(curr_client->ipcs);
 589         }
 590     }
 591 
 592     free(minor_version);
 593     free(major_version);
 594     free(client_name);
 595 
 596     /* hello messages should never be processed further */
 597     return FALSE;
 598 }
 599 
 600 enum crmd_fsa_input
 601 handle_message(xmlNode * msg, enum crmd_fsa_cause cause)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603     const char *type = NULL;
 604 
 605     CRM_CHECK(msg != NULL, return I_NULL);
 606 
 607     type = crm_element_value(msg, F_CRM_MSG_TYPE);
 608     if (crm_str_eq(type, XML_ATTR_REQUEST, TRUE)) {
 609         return handle_request(msg, cause);
 610 
 611     } else if (crm_str_eq(type, XML_ATTR_RESPONSE, TRUE)) {
 612         handle_response(msg);
 613         return I_NULL;
 614     }
 615 
 616     crm_err("Unknown message type: %s", type);
 617     return I_NULL;
 618 }
 619 
 620 static enum crmd_fsa_input
 621 handle_failcount_op(xmlNode * stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 622 {
 623     const char *rsc = NULL;
 624     const char *uname = NULL;
 625     const char *op = NULL;
 626     const char *interval = NULL;
 627     int interval_ms = 0;
 628     gboolean is_remote_node = FALSE;
 629     xmlNode *xml_op = get_message_xml(stored_msg, F_CRM_DATA);
 630 
 631     if (xml_op) {
 632         xmlNode *xml_rsc = first_named_child(xml_op, XML_CIB_TAG_RESOURCE);
 633         xmlNode *xml_attrs = first_named_child(xml_op, XML_TAG_ATTRS);
 634 
 635         if (xml_rsc) {
 636             rsc = ID(xml_rsc);
 637         }
 638         if (xml_attrs) {
 639             op = crm_element_value(xml_attrs,
 640                                    CRM_META "_" XML_RSC_ATTR_CLEAR_OP);
 641             interval = crm_element_value(xml_attrs,
 642                                          CRM_META "_" XML_RSC_ATTR_CLEAR_INTERVAL);
 643             interval_ms = crm_parse_int(interval, "0");
 644         }
 645     }
 646     uname = crm_element_value(xml_op, XML_LRM_ATTR_TARGET);
 647 
 648     if ((rsc == NULL) || (uname == NULL)) {
 649         crm_log_xml_warn(stored_msg, "invalid failcount op");
 650         return I_NULL;
 651     }
 652 
 653     if (crm_element_value(xml_op, XML_LRM_ATTR_ROUTER_NODE)) {
 654         is_remote_node = TRUE;
 655     }
 656     update_attrd_clear_failures(uname, rsc, op, interval, is_remote_node);
 657     lrm_clear_last_failure(rsc, uname, op, interval_ms);
 658 
 659     return I_NULL;
 660 }
 661 
 662 /*!
 663  * \brief Handle a CRM_OP_REMOTE_STATE message by updating remote peer cache
 664  *
 665  * \param[in] msg  Message XML
 666  *
 667  * \return Next FSA input
 668  */
 669 static enum crmd_fsa_input
 670 handle_remote_state(xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 671 {
 672     const char *remote_uname = ID(msg);
 673     const char *remote_is_up = crm_element_value(msg, XML_NODE_IN_CLUSTER);
 674     crm_node_t *remote_peer;
 675 
 676     CRM_CHECK(remote_uname && remote_is_up, return I_NULL);
 677 
 678     remote_peer = crm_remote_peer_get(remote_uname);
 679     CRM_CHECK(remote_peer, return I_NULL);
 680 
 681     crm_update_peer_state(__FUNCTION__, remote_peer,
 682                           crm_is_true(remote_is_up)?
 683                           CRM_NODE_MEMBER : CRM_NODE_LOST, 0);
 684     return I_NULL;
 685 }
 686 
 687 enum crmd_fsa_input
 688 handle_request(xmlNode * stored_msg, enum crmd_fsa_cause cause)
     /* [previous][next][first][last][top][bottom][index][help] */
 689 {
 690     xmlNode *msg = NULL;
 691     const char *op = crm_element_value(stored_msg, F_CRM_TASK);
 692 
 693     /* Optimize this for the DC - it has the most to do */
 694 
 695     if (op == NULL) {
 696         crm_log_xml_err(stored_msg, "Bad message");
 697         return I_NULL;
 698     }
 699 
 700     if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
 701         const char *from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 702         crm_node_t *node = crm_find_peer(0, from);
 703 
 704         crm_update_peer_expected(__FUNCTION__, node, CRMD_JOINSTATE_DOWN);
 705         if(AM_I_DC == FALSE) {
 706             return I_NULL; /* Done */
 707         }
 708     }
 709 
 710     /*========== DC-Only Actions ==========*/
 711     if (AM_I_DC) {
 712         if (strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
 713             return I_NODE_JOIN;
 714 
 715         } else if (strcmp(op, CRM_OP_JOIN_REQUEST) == 0) {
 716             return I_JOIN_REQUEST;
 717 
 718         } else if (strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
 719             return I_JOIN_RESULT;
 720 
 721         } else if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
 722             const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 723             gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
 724 
 725             if (is_set(fsa_input_register, R_SHUTDOWN)) {
 726                 crm_info("Shutting ourselves down (DC)");
 727                 return I_STOP;
 728 
 729             } else if (dc_match) {
 730                 crm_err("We didn't ask to be shut down, yet our"
 731                         " TE is telling us to. Better get out now!");
 732                 return I_TERMINATE;
 733 
 734             } else if (fsa_state != S_STOPPING) {
 735                 crm_err("Another node is asking us to shutdown" " but we think we're ok.");
 736                 return I_ELECTION;
 737             }
 738 
 739         } else if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
 740             /* a slave wants to shut down */
 741             /* create cib fragment and add to message */
 742             return handle_shutdown_request(stored_msg);
 743 
 744         } else if (strcmp(op, CRM_OP_REMOTE_STATE) == 0) {
 745             /* a remote connection host is letting us know the node state */
 746             return handle_remote_state(stored_msg);
 747         }
 748     }
 749 
 750     /*========== common actions ==========*/
 751     if (strcmp(op, CRM_OP_NOVOTE) == 0) {
 752         ha_msg_input_t fsa_input;
 753 
 754         fsa_input.msg = stored_msg;
 755         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
 756                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE, __FUNCTION__);
 757 
 758     } else if (strcmp(op, CRM_OP_THROTTLE) == 0) {
 759         throttle_update(stored_msg);
 760         if (AM_I_DC && transition_graph != NULL) {
 761             if (transition_graph->complete == FALSE) {
 762                 crm_debug("The throttle changed. Trigger a graph.");
 763                 trigger_graph();
 764             }
 765         }
 766         return I_NULL;
 767 
 768     } else if (strcmp(op, CRM_OP_CLEAR_FAILCOUNT) == 0) {
 769         return handle_failcount_op(stored_msg);
 770 
 771     } else if (strcmp(op, CRM_OP_VOTE) == 0) {
 772         /* count the vote and decide what to do after that */
 773         ha_msg_input_t fsa_input;
 774 
 775         fsa_input.msg = stored_msg;
 776         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
 777                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE, __FUNCTION__);
 778 
 779         /* Sometimes we _must_ go into S_ELECTION */
 780         if (fsa_state == S_HALT) {
 781             crm_debug("Forcing an election from S_HALT");
 782             return I_ELECTION;
 783 #if 0
 784         } else if (AM_I_DC) {
 785             /* This is the old way of doing things but what is gained? */
 786             return I_ELECTION;
 787 #endif
 788         }
 789 
 790     } else if (strcmp(op, CRM_OP_JOIN_OFFER) == 0) {
 791         crm_debug("Raising I_JOIN_OFFER: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
 792         return I_JOIN_OFFER;
 793 
 794     } else if (strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
 795         crm_debug("Raising I_JOIN_RESULT: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
 796         return I_JOIN_RESULT;
 797 
 798     } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0
 799                || strcmp(op, CRM_OP_LRM_FAIL) == 0
 800                || strcmp(op, CRM_OP_LRM_REFRESH) == 0 || strcmp(op, CRM_OP_REPROBE) == 0) {
 801 
 802         crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
 803         return I_ROUTER;
 804 
 805     } else if (strcmp(op, CRM_OP_NOOP) == 0) {
 806         return I_NULL;
 807 
 808     } else if (strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {
 809 
 810         crm_shutdown(SIGTERM);
 811         /*return I_SHUTDOWN; */
 812         return I_NULL;
 813 
 814         /*========== (NOT_DC)-Only Actions ==========*/
 815     } else if (AM_I_DC == FALSE && strcmp(op, CRM_OP_SHUTDOWN) == 0) {
 816 
 817         const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 818         gboolean dc_match = safe_str_eq(host_from, fsa_our_dc);
 819 
 820         if (dc_match || fsa_our_dc == NULL) {
 821             if (is_set(fsa_input_register, R_SHUTDOWN) == FALSE) {
 822                 crm_err("We didn't ask to be shut down, yet our DC is telling us to.");
 823                 set_bit(fsa_input_register, R_STAYDOWN);
 824                 return I_STOP;
 825             }
 826             crm_info("Shutting down");
 827             return I_STOP;
 828 
 829         } else {
 830             crm_warn("Discarding %s op from %s", op, host_from);
 831         }
 832 
 833     } else if (strcmp(op, CRM_OP_PING) == 0) {
 834         /* eventually do some stuff to figure out
 835          * if we /are/ ok
 836          */
 837         const char *sys_to = crm_element_value(stored_msg, F_CRM_SYS_TO);
 838         xmlNode *ping = create_xml_node(NULL, XML_CRM_TAG_PING);
 839 
 840         crm_xml_add(ping, XML_PING_ATTR_STATUS, "ok");
 841         crm_xml_add(ping, XML_PING_ATTR_SYSFROM, sys_to);
 842         crm_xml_add(ping, "crmd_state", fsa_state2string(fsa_state));
 843 
 844         /* Ok, so technically not so interesting, but CTS needs to see this */
 845         crm_notice("Current ping state: %s", fsa_state2string(fsa_state));
 846 
 847         msg = create_reply(stored_msg, ping);
 848         if (msg) {
 849             (void)relay_message(msg, TRUE);
 850         }
 851 
 852         free_xml(ping);
 853         free_xml(msg);
 854 
 855     } else if (strcmp(op, CRM_OP_RM_NODE_CACHE) == 0) {
 856         int id = 0;
 857         const char *name = NULL;
 858 
 859         crm_element_value_int(stored_msg, XML_ATTR_ID, &id);
 860         name = crm_element_value(stored_msg, XML_ATTR_UNAME);
 861 
 862         if(cause == C_IPC_MESSAGE) {
 863             msg = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
 864             if (send_cluster_message(NULL, crm_msg_crmd, msg, TRUE) == FALSE) {
 865                 crm_err("Could not instruct peers to remove references to node %s/%u", name, id);
 866             } else {
 867                 crm_notice("Instructing peers to remove references to node %s/%u", name, id);
 868             }
 869             free_xml(msg);
 870 
 871         } else {
 872             reap_crm_member(id, name);
 873 
 874             /* If we're forgetting this node, also forget any failures to fence
 875              * it, so we don't carry that over to any node added later with the
 876              * same name.
 877              */
 878             st_fail_count_reset(name);
 879         }
 880 
 881     } else if (strcmp(op, CRM_OP_MAINTENANCE_NODES) == 0) {
 882         xmlNode *xml = get_message_xml(stored_msg, F_CRM_DATA);
 883 
 884         remote_ra_process_maintenance_nodes(xml);
 885 
 886     } else {
 887         crm_err("Unexpected request (%s) sent to %s", op, AM_I_DC ? "the DC" : "non-DC node");
 888         crm_log_xml_err(stored_msg, "Unexpected");
 889     }
 890 
 891     return I_NULL;
 892 }
 893 
 894 void
 895 handle_response(xmlNode * stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 896 {
 897     const char *op = crm_element_value(stored_msg, F_CRM_TASK);
 898 
 899     if (op == NULL) {
 900         crm_log_xml_err(stored_msg, "Bad message");
 901 
 902     } else if (AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) {
 903         /* Check if the PE answer been superseded by a subsequent request? */
 904         const char *msg_ref = crm_element_value(stored_msg, XML_ATTR_REFERENCE);
 905 
 906         if (msg_ref == NULL) {
 907             crm_err("%s - Ignoring calculation with no reference", op);
 908 
 909         } else if (safe_str_eq(msg_ref, fsa_pe_ref)) {
 910             ha_msg_input_t fsa_input;
 911 
 912             fsa_input.msg = stored_msg;
 913             register_fsa_input_later(C_IPC_MESSAGE, I_PE_SUCCESS, &fsa_input);
 914             crm_trace("Completed: %s...", fsa_pe_ref);
 915 
 916         } else {
 917             crm_info("%s calculation %s is obsolete", op, msg_ref);
 918         }
 919 
 920     } else if (strcmp(op, CRM_OP_VOTE) == 0
 921                || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0) {
 922 
 923     } else {
 924         const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 925 
 926         crm_err("Unexpected response (op=%s, src=%s) sent to the %s",
 927                 op, host_from, AM_I_DC ? "DC" : "CRMd");
 928     }
 929 }
 930 
 931 enum crmd_fsa_input
 932 handle_shutdown_request(xmlNode * stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 933 {
 934     /* handle here to avoid potential version issues
 935      *   where the shutdown message/procedure may have
 936      *   been changed in later versions.
 937      *
 938      * This way the DC is always in control of the shutdown
 939      */
 940 
 941     char *now_s = NULL;
 942     time_t now = time(NULL);
 943     const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 944 
 945     if (host_from == NULL) {
 946         /* we're shutting down and the DC */
 947         host_from = fsa_our_uname;
 948     }
 949 
 950     crm_info("Creating shutdown request for %s (state=%s)", host_from, fsa_state2string(fsa_state));
 951     crm_log_xml_trace(stored_msg, "message");
 952 
 953     now_s = crm_itoa(now);
 954     update_attrd(host_from, XML_CIB_ATTR_SHUTDOWN, now_s, NULL, FALSE);
 955     free(now_s);
 956 
 957     /* will be picked up by the TE as long as its running */
 958     return I_NULL;
 959 }
 960 
 961 /* msg is deleted by the time this returns */
 962 extern gboolean process_te_message(xmlNode * msg, xmlNode * xml_data);
 963 
 964 gboolean
 965 send_msg_via_ipc(xmlNode * msg, const char *sys)
     /* [previous][next][first][last][top][bottom][index][help] */
 966 {
 967     gboolean send_ok = TRUE;
 968     crm_client_t *client_channel = crm_client_get_by_id(sys);
 969 
 970     if (crm_element_value(msg, F_CRM_HOST_FROM) == NULL) {
 971         crm_xml_add(msg, F_CRM_HOST_FROM, fsa_our_uname);
 972     }
 973 
 974     if (client_channel != NULL) {
 975         /* Transient clients such as crmadmin */
 976         send_ok = crm_ipcs_send(client_channel, 0, msg, crm_ipc_server_event);
 977 
 978     } else if (sys != NULL && strcmp(sys, CRM_SYSTEM_TENGINE) == 0) {
 979         xmlNode *data = get_message_xml(msg, F_CRM_DATA);
 980 
 981         process_te_message(msg, data);
 982 
 983     } else if (sys != NULL && strcmp(sys, CRM_SYSTEM_LRMD) == 0) {
 984         fsa_data_t fsa_data;
 985         ha_msg_input_t fsa_input;
 986 
 987         fsa_input.msg = msg;
 988         fsa_input.xml = get_message_xml(msg, F_CRM_DATA);
 989 
 990         fsa_data.id = 0;
 991         fsa_data.actions = 0;
 992         fsa_data.data = &fsa_input;
 993         fsa_data.fsa_input = I_MESSAGE;
 994         fsa_data.fsa_cause = C_IPC_MESSAGE;
 995         fsa_data.origin = __FUNCTION__;
 996         fsa_data.data_type = fsa_dt_ha_msg;
 997 
 998 #ifdef FSA_TRACE
 999         crm_trace("Invoking action A_LRM_INVOKE (%.16llx)", A_LRM_INVOKE);
1000 #endif
1001         do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, fsa_state, I_MESSAGE, &fsa_data);
1002 
1003     } else if (sys != NULL && crmd_is_proxy_session(sys)) {
1004         crmd_proxy_send(sys, msg);
1005 
1006     } else {
1007         crm_debug("Unknown Sub-system (%s)... discarding message.", crm_str(sys));
1008         send_ok = FALSE;
1009     }
1010 
1011     return send_ok;
1012 }
1013 
1014 ha_msg_input_t *
1015 new_ha_msg_input(xmlNode * orig)
     /* [previous][next][first][last][top][bottom][index][help] */
1016 {
1017     ha_msg_input_t *input_copy = NULL;
1018 
1019     input_copy = calloc(1, sizeof(ha_msg_input_t));
1020     input_copy->msg = orig;
1021     input_copy->xml = get_message_xml(input_copy->msg, F_CRM_DATA);
1022     return input_copy;
1023 }
1024 
1025 void
1026 delete_ha_msg_input(ha_msg_input_t * orig)
     /* [previous][next][first][last][top][bottom][index][help] */
1027 {
1028     if (orig == NULL) {
1029         return;
1030     }
1031     free_xml(orig->msg);
1032     free(orig);
1033 }
1034 
1035 /*!
1036  * \internal
1037  * \brief Notify the DC of a remote node state change
1038  *
1039  * \param[in] node_name  Node's name
1040  * \param[in] node_up    TRUE if node is up, FALSE if down
1041  */
1042 void
1043 send_remote_state_message(const char *node_name, gboolean node_up)
     /* [previous][next][first][last][top][bottom][index][help] */
1044 {
1045     /* If we don't have a DC, or the message fails, we have a failsafe:
1046      * the DC will eventually pick up the change via the CIB node state.
1047      * The message allows it to happen sooner if possible.
1048      */
1049     if (fsa_our_dc) {
1050         xmlNode *msg = create_request(CRM_OP_REMOTE_STATE, NULL, fsa_our_dc,
1051                                       CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL);
1052 
1053         crm_info("Notifying DC %s of pacemaker_remote node %s %s",
1054                  fsa_our_dc, node_name, (node_up? "coming up" : "going down"));
1055         crm_xml_add(msg, XML_ATTR_ID, node_name);
1056         crm_xml_add_boolean(msg, XML_NODE_IN_CLUSTER, node_up);
1057         send_cluster_message(crm_get_peer(0, fsa_our_dc), crm_msg_crmd, msg,
1058                              TRUE);
1059         free_xml(msg);
1060     } else {
1061         crm_debug("No DC to notify of pacemaker_remote node %s %s",
1062                   node_name, (node_up? "coming up" : "going down"));
1063     }
1064 }
1065 

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