This source file includes following definitions.
- cib_read_legacy_mode
- cib_legacy_mode
- cib_ipc_accept
- cib_ipc_created
- cib_ipc_dispatch_rw
- cib_ipc_dispatch_ro
- cib_ipc_closed
- cib_ipc_destroy
- cib_common_callback_worker
- cib_common_callback
- cib_digester_cb
- process_ping_reply
- do_local_notify
- local_notify_destroy_callback
- check_local_notify
- queue_local_notify
- parse_local_options_v1
- parse_local_options_v2
- parse_local_options
- parse_peer_options_v1
- parse_peer_options_v2
- parse_peer_options
- forward_request
- send_peer_reply
- cib_process_request
- cib_process_command
- cib_GCompareFunc
- cib_ha_peer_callback
- cib_peer_callback
- cib_client_status_callback
- cib_ccm_dispatch
- cib_ccm_msg_callback
- can_write
- cib_force_exit
- disconnect_remote_client
- cib_shutdown
- initiate_exit
- terminate_cib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20
21 #include <sys/param.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <fcntl.h>
29
30 #include <crm/crm.h>
31 #include <crm/cib.h>
32 #include <crm/msg_xml.h>
33 #include <crm/cluster/internal.h>
34
35 #include <crm/common/xml.h>
36
37 #include <cibio.h>
38 #include <callbacks.h>
39 #include <cibmessages.h>
40 #include <notify.h>
41 #include "common.h"
42
43 static unsigned long cib_local_bcast_num = 0;
44
45 typedef struct cib_local_notify_s {
46 xmlNode *notify_src;
47 char *client_id;
48 gboolean from_peer;
49 gboolean sync_reply;
50 } cib_local_notify_t;
51
52 int next_client_id = 0;
53
54 #if SUPPORT_PLUGIN
55 gboolean legacy_mode = TRUE;
56 #else
57 gboolean legacy_mode = FALSE;
58 #endif
59
60 qb_ipcs_service_t *ipcs_ro = NULL;
61 qb_ipcs_service_t *ipcs_rw = NULL;
62 qb_ipcs_service_t *ipcs_shm = NULL;
63
64 gint cib_GCompareFunc(gconstpointer a, gconstpointer b);
65 gboolean can_write(int flags);
66 void send_cib_replace(const xmlNode * sync_request, const char *host);
67 void cib_process_request(xmlNode * request, gboolean privileged, gboolean force_synchronous,
68 gboolean from_peer, crm_client_t * cib_client);
69
70
71 int cib_process_command(xmlNode * request, xmlNode ** reply,
72 xmlNode ** cib_diff, gboolean privileged);
73
74 gboolean cib_common_callback(qb_ipcs_connection_t * c, void *data, size_t size,
75 gboolean privileged);
76
77 #if !SUPPORT_PLUGIN
78 static gboolean cib_read_legacy_mode(void)
79 {
80 static gboolean init = TRUE;
81 static gboolean legacy = FALSE;
82
83 if(init) {
84 init = FALSE;
85 legacy = daemon_option_enabled("cib", "legacy");
86 if(legacy) {
87 crm_notice("Enabled legacy mode");
88 }
89 }
90
91 return legacy;
92 }
93 #endif
94
95 gboolean cib_legacy_mode(void)
96 {
97 #if SUPPORT_PLUGIN
98 return TRUE;
99 #else
100 if(cib_read_legacy_mode()) {
101 return TRUE;
102 }
103 return legacy_mode;
104 #endif
105 }
106
107
108 static int32_t
109 cib_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
110 {
111 crm_trace("Connection %p", c);
112 if (cib_shutdown_flag) {
113 crm_info("Ignoring new client [%d] during shutdown", crm_ipcs_client_pid(c));
114 return -EPERM;
115 }
116
117 if (crm_client_new(c, uid, gid) == NULL) {
118 return -EIO;
119 }
120 return 0;
121 }
122
123 static void
124 cib_ipc_created(qb_ipcs_connection_t * c)
125 {
126 crm_trace("Connection %p", c);
127 }
128
129 static int32_t
130 cib_ipc_dispatch_rw(qb_ipcs_connection_t * c, void *data, size_t size)
131 {
132 crm_client_t *client = crm_client_get(c);
133
134 crm_trace("%p message from %s", c, client->id);
135 return cib_common_callback(c, data, size, TRUE);
136 }
137
138 static int32_t
139 cib_ipc_dispatch_ro(qb_ipcs_connection_t * c, void *data, size_t size)
140 {
141 crm_client_t *client = crm_client_get(c);
142
143 crm_trace("%p message from %s", c, client->id);
144 return cib_common_callback(c, data, size, FALSE);
145 }
146
147
148 static int32_t
149 cib_ipc_closed(qb_ipcs_connection_t * c)
150 {
151 crm_client_t *client = crm_client_get(c);
152
153 if (client == NULL) {
154 return 0;
155 }
156 crm_trace("Connection %p", c);
157 crm_client_destroy(client);
158 return 0;
159 }
160
161 static void
162 cib_ipc_destroy(qb_ipcs_connection_t * c)
163 {
164 crm_trace("Connection %p", c);
165 cib_ipc_closed(c);
166 if (cib_shutdown_flag) {
167 cib_shutdown(0);
168 }
169 }
170
171 struct qb_ipcs_service_handlers ipc_ro_callbacks = {
172 .connection_accept = cib_ipc_accept,
173 .connection_created = cib_ipc_created,
174 .msg_process = cib_ipc_dispatch_ro,
175 .connection_closed = cib_ipc_closed,
176 .connection_destroyed = cib_ipc_destroy
177 };
178
179 struct qb_ipcs_service_handlers ipc_rw_callbacks = {
180 .connection_accept = cib_ipc_accept,
181 .connection_created = cib_ipc_created,
182 .msg_process = cib_ipc_dispatch_rw,
183 .connection_closed = cib_ipc_closed,
184 .connection_destroyed = cib_ipc_destroy
185 };
186
187 void
188 cib_common_callback_worker(uint32_t id, uint32_t flags, xmlNode * op_request,
189 crm_client_t * cib_client, gboolean privileged)
190 {
191 const char *op = crm_element_value(op_request, F_CIB_OPERATION);
192
193 if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
194 if (flags & crm_ipc_client_response) {
195 xmlNode *ack = create_xml_node(NULL, __FUNCTION__);
196
197 crm_xml_add(ack, F_CIB_OPERATION, CRM_OP_REGISTER);
198 crm_xml_add(ack, F_CIB_CLIENTID, cib_client->id);
199 crm_ipcs_send(cib_client, id, ack, flags);
200 cib_client->request_id = 0;
201 free_xml(ack);
202 }
203 return;
204
205 } else if (crm_str_eq(op, T_CIB_NOTIFY, TRUE)) {
206
207 int on_off = 0;
208 long long bit = 0;
209 const char *type = crm_element_value(op_request, F_CIB_NOTIFY_TYPE);
210
211 crm_element_value_int(op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);
212
213 crm_debug("Setting %s callbacks for %s (%s): %s",
214 type, cib_client->name, cib_client->id, on_off ? "on" : "off");
215
216 if (safe_str_eq(type, T_CIB_POST_NOTIFY)) {
217 bit = cib_notify_post;
218
219 } else if (safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
220 bit = cib_notify_pre;
221
222 } else if (safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
223 bit = cib_notify_confirm;
224
225 } else if (safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
226 bit = cib_notify_diff;
227
228 } else if (safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) {
229 bit = cib_notify_replace;
230 }
231
232 if (on_off) {
233 set_bit(cib_client->options, bit);
234 } else {
235 clear_bit(cib_client->options, bit);
236 }
237
238 if (flags & crm_ipc_client_response) {
239
240 crm_ipcs_send_ack(cib_client, id, flags, "ack", __FUNCTION__, __LINE__);
241 }
242 return;
243 }
244
245 cib_process_request(op_request, FALSE, privileged, FALSE, cib_client);
246 }
247
248 int32_t
249 cib_common_callback(qb_ipcs_connection_t * c, void *data, size_t size, gboolean privileged)
250 {
251 uint32_t id = 0;
252 uint32_t flags = 0;
253 int call_options = 0;
254 crm_client_t *cib_client = crm_client_get(c);
255 xmlNode *op_request = crm_ipcs_recv(cib_client, data, size, &id, &flags);
256
257 if (op_request) {
258 crm_element_value_int(op_request, F_CIB_CALLOPTS, &call_options);
259 }
260
261 if (op_request == NULL) {
262 crm_trace("Invalid message from %p", c);
263 crm_ipcs_send_ack(cib_client, id, flags, "nack", __FUNCTION__, __LINE__);
264 return 0;
265
266 } else if(cib_client == NULL) {
267 crm_trace("Invalid client %p", c);
268 return 0;
269 }
270
271 if (is_set(call_options, cib_sync_call)) {
272 CRM_LOG_ASSERT(flags & crm_ipc_client_response);
273 CRM_LOG_ASSERT(cib_client->request_id == 0);
274 cib_client->request_id = id;
275 }
276
277 if (cib_client->name == NULL) {
278 const char *value = crm_element_value(op_request, F_CIB_CLIENTNAME);
279
280 if (value == NULL) {
281 cib_client->name = crm_itoa(cib_client->pid);
282 } else {
283 cib_client->name = strdup(value);
284 if (crm_is_daemon_name(value)) {
285 set_bit(cib_client->options, cib_is_daemon);
286 }
287 }
288 }
289
290
291 if (is_set(cib_client->options, cib_is_daemon)) {
292 const char *qmax = cib_config_lookup("cluster-ipc-limit");
293
294 if (crm_set_client_queue_max(cib_client, qmax)) {
295 crm_trace("IPC threshold for %s[%u] is now %u",
296 cib_client->name, cib_client->pid, cib_client->queue_max);
297 }
298 }
299
300 crm_xml_add(op_request, F_CIB_CLIENTID, cib_client->id);
301 crm_xml_add(op_request, F_CIB_CLIENTNAME, cib_client->name);
302
303 #if ENABLE_ACL
304 CRM_LOG_ASSERT(cib_client->user != NULL);
305 crm_acl_get_set_user(op_request, F_CIB_USER, cib_client->user);
306 #endif
307
308 crm_log_xml_trace(op_request, "Client[inbound]");
309
310 cib_common_callback_worker(id, flags, op_request, cib_client, privileged);
311 free_xml(op_request);
312
313 return 0;
314 }
315
316 static uint64_t ping_seq = 0;
317 static char *ping_digest = NULL;
318 static bool ping_modified_since = FALSE;
319 int sync_our_cib(xmlNode * request, gboolean all);
320
321 static gboolean
322 cib_digester_cb(gpointer data)
323 {
324 if (cib_is_master) {
325 char buffer[32];
326 xmlNode *ping = create_xml_node(NULL, "ping");
327
328 ping_seq++;
329 free(ping_digest);
330 ping_digest = NULL;
331 ping_modified_since = FALSE;
332 snprintf(buffer, 32, U64T, ping_seq);
333 crm_trace("Requesting peer digests (%s)", buffer);
334
335 crm_xml_add(ping, F_TYPE, "cib");
336 crm_xml_add(ping, F_CIB_OPERATION, CRM_OP_PING);
337 crm_xml_add(ping, F_CIB_PING_ID, buffer);
338
339 crm_xml_add(ping, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
340 send_cluster_message(NULL, crm_msg_cib, ping, TRUE);
341
342 free_xml(ping);
343 }
344 return FALSE;
345 }
346
347 static void
348 process_ping_reply(xmlNode *reply)
349 {
350 uint64_t seq = 0;
351 const char *host = crm_element_value(reply, F_ORIG);
352
353 xmlNode *pong = get_message_xml(reply, F_CIB_CALLDATA);
354 const char *seq_s = crm_element_value(pong, F_CIB_PING_ID);
355 const char *digest = crm_element_value(pong, XML_ATTR_DIGEST);
356
357 if (seq_s) {
358 seq = crm_int_helper(seq_s, NULL);
359 }
360
361 if(digest == NULL) {
362 crm_trace("Ignoring ping reply %s from %s with no digest", seq_s, host);
363
364 } else if(seq != ping_seq) {
365 crm_trace("Ignoring out of sequence ping reply %s from %s", seq_s, host);
366
367 } else if(ping_modified_since) {
368 crm_trace("Ignoring ping reply %s from %s: cib updated since", seq_s, host);
369
370 } else {
371 const char *version = crm_element_value(pong, XML_ATTR_CRM_VERSION);
372
373 if(ping_digest == NULL) {
374 crm_trace("Calculating new digest");
375 ping_digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, version);
376 }
377
378 crm_trace("Processing ping reply %s from %s (%s)", seq_s, host, digest);
379 if(safe_str_eq(ping_digest, digest) == FALSE) {
380 xmlNode *remote_cib = get_message_xml(pong, F_CIB_CALLDATA);
381
382 crm_notice("Local CIB %s.%s.%s.%s differs from %s: %s.%s.%s.%s %p",
383 crm_element_value(the_cib, XML_ATTR_GENERATION_ADMIN),
384 crm_element_value(the_cib, XML_ATTR_GENERATION),
385 crm_element_value(the_cib, XML_ATTR_NUMUPDATES),
386 ping_digest, host,
387 remote_cib?crm_element_value(remote_cib, XML_ATTR_GENERATION_ADMIN):"_",
388 remote_cib?crm_element_value(remote_cib, XML_ATTR_GENERATION):"_",
389 remote_cib?crm_element_value(remote_cib, XML_ATTR_NUMUPDATES):"_",
390 digest, remote_cib);
391
392 if(remote_cib && remote_cib->children) {
393
394 xml_calculate_changes(the_cib, remote_cib);
395 xml_log_changes(LOG_INFO, __FUNCTION__, remote_cib);
396 crm_trace("End of differences");
397 }
398
399 free_xml(remote_cib);
400 sync_our_cib(reply, FALSE);
401 }
402 }
403 }
404
405 static void
406 do_local_notify(xmlNode * notify_src, const char *client_id,
407 gboolean sync_reply, gboolean from_peer)
408 {
409
410 crm_client_t *client_obj = NULL;
411 int local_rc = pcmk_ok;
412 int call_id = 0;
413
414 crm_element_value_int(notify_src, F_CIB_CALLID, &call_id);
415
416 if (client_id != NULL) {
417 client_obj = crm_client_get_by_id(client_id);
418 }
419
420 if (client_obj == NULL) {
421 local_rc = -ECONNRESET;
422 crm_trace("No client to sent response %d to, F_CIB_CLIENTID not set.", call_id);
423
424 } else {
425 int rid = 0;
426
427 if (sync_reply) {
428 if (client_obj->ipcs) {
429 CRM_LOG_ASSERT(client_obj->request_id);
430
431 rid = client_obj->request_id;
432 client_obj->request_id = 0;
433
434 crm_trace("Sending response %d to %s %s",
435 rid, client_obj->name,
436 from_peer ? "(originator of delegated request)" : "");
437 } else {
438 crm_trace("Sending response [call %d] to %s %s",
439 call_id, client_obj->name, from_peer ? "(originator of delegated request)" : "");
440 }
441
442 } else {
443 crm_trace("Sending event %d to %s %s",
444 call_id, client_obj->name, from_peer ? "(originator of delegated request)" : "");
445 }
446
447 switch (client_obj->kind) {
448 case CRM_CLIENT_IPC:
449 if (crm_ipcs_send(client_obj, rid, notify_src, sync_reply?crm_ipc_flags_none:crm_ipc_server_event) < 0) {
450 local_rc = -ENOMSG;
451 }
452 break;
453 #ifdef HAVE_GNUTLS_GNUTLS_H
454 case CRM_CLIENT_TLS:
455 #endif
456 case CRM_CLIENT_TCP:
457 crm_remote_send(client_obj->remote, notify_src);
458 break;
459 default:
460 crm_err("Unknown transport %d for %s", client_obj->kind, client_obj->name);
461 }
462 }
463
464 if (local_rc != pcmk_ok && client_obj != NULL) {
465 crm_warn("%sSync reply to %s failed: %s",
466 sync_reply ? "" : "A-",
467 client_obj ? client_obj->name : "<unknown>", pcmk_strerror(local_rc));
468 }
469 }
470
471 static void
472 local_notify_destroy_callback(gpointer data)
473 {
474 cib_local_notify_t *notify = data;
475
476 free_xml(notify->notify_src);
477 free(notify->client_id);
478 free(notify);
479 }
480
481 static void
482 check_local_notify(int bcast_id)
483 {
484 cib_local_notify_t *notify = NULL;
485
486 if (!local_notify_queue) {
487 return;
488 }
489
490 notify = g_hash_table_lookup(local_notify_queue, GINT_TO_POINTER(bcast_id));
491
492 if (notify) {
493 do_local_notify(notify->notify_src, notify->client_id, notify->sync_reply,
494 notify->from_peer);
495 g_hash_table_remove(local_notify_queue, GINT_TO_POINTER(bcast_id));
496 }
497 }
498
499 static void
500 queue_local_notify(xmlNode * notify_src, const char *client_id, gboolean sync_reply,
501 gboolean from_peer)
502 {
503 cib_local_notify_t *notify = calloc(1, sizeof(cib_local_notify_t));
504
505 notify->notify_src = notify_src;
506 notify->client_id = strdup(client_id);
507 notify->sync_reply = sync_reply;
508 notify->from_peer = from_peer;
509
510 if (!local_notify_queue) {
511 local_notify_queue = g_hash_table_new_full(g_direct_hash,
512 g_direct_equal, NULL,
513 local_notify_destroy_callback);
514 }
515
516 g_hash_table_insert(local_notify_queue, GINT_TO_POINTER(cib_local_bcast_num), notify);
517 }
518
519 static void
520 parse_local_options_v1(crm_client_t * cib_client, int call_type, int call_options, const char *host,
521 const char *op, gboolean * local_notify, gboolean * needs_reply,
522 gboolean * process, gboolean * needs_forward)
523 {
524 if (cib_op_modifies(call_type)
525 && !(call_options & cib_inhibit_bcast)) {
526
527 *needs_reply = TRUE;
528 } else {
529 *needs_reply = FALSE;
530 }
531
532 if (host == NULL && (call_options & cib_scope_local)) {
533 crm_trace("Processing locally scoped %s op from %s", op, cib_client->name);
534 *local_notify = TRUE;
535
536 } else if (host == NULL && cib_is_master) {
537 crm_trace("Processing master %s op locally from %s", op, cib_client->name);
538 *local_notify = TRUE;
539
540 } else if (safe_str_eq(host, cib_our_uname)) {
541 crm_trace("Processing locally addressed %s op from %s", op, cib_client->name);
542 *local_notify = TRUE;
543
544 } else if (stand_alone) {
545 *needs_forward = FALSE;
546 *local_notify = TRUE;
547 *process = TRUE;
548
549 } else {
550 crm_trace("%s op from %s needs to be forwarded to %s",
551 op, cib_client->name, host ? host : "the master instance");
552 *needs_forward = TRUE;
553 *process = FALSE;
554 }
555 }
556
557 static void
558 parse_local_options_v2(crm_client_t * cib_client, int call_type, int call_options, const char *host,
559 const char *op, gboolean * local_notify, gboolean * needs_reply,
560 gboolean * process, gboolean * needs_forward)
561 {
562 if (cib_op_modifies(call_type)) {
563 if(safe_str_eq(op, CIB_OP_MASTER) || safe_str_eq(op, CIB_OP_SLAVE)) {
564
565 *process = TRUE;
566 *needs_reply = FALSE;
567 *local_notify = TRUE;
568 *needs_forward = FALSE;
569 return;
570
571 } else {
572
573 *needs_reply = TRUE;
574 *needs_forward = TRUE;
575 *process = FALSE;
576 crm_trace("%s op from %s needs to be forwarded to %s",
577 op, cib_client->name, host ? host : "the master instance");
578 return;
579 }
580 }
581
582
583 *process = TRUE;
584 *needs_reply = FALSE;
585 *local_notify = TRUE;
586 *needs_forward = FALSE;
587
588 if (stand_alone) {
589 crm_trace("Processing %s op from %s (stand-alone)", op, cib_client->name);
590
591 } else if (host == NULL) {
592 crm_trace("Processing unaddressed %s op from %s", op, cib_client->name);
593
594 } else if (safe_str_eq(host, cib_our_uname)) {
595 crm_trace("Processing locally addressed %s op from %s", op, cib_client->name);
596
597 } else {
598 crm_trace("%s op from %s needs to be forwarded to %s", op, cib_client->name, host);
599 *needs_forward = TRUE;
600 *process = FALSE;
601 }
602 }
603
604 static void
605 parse_local_options(crm_client_t * cib_client, int call_type, int call_options, const char *host,
606 const char *op, gboolean * local_notify, gboolean * needs_reply,
607 gboolean * process, gboolean * needs_forward)
608 {
609 if(cib_legacy_mode()) {
610 parse_local_options_v1(cib_client, call_type, call_options, host,
611 op, local_notify, needs_reply, process, needs_forward);
612 } else {
613 parse_local_options_v2(cib_client, call_type, call_options, host,
614 op, local_notify, needs_reply, process, needs_forward);
615 }
616 }
617
618 static gboolean
619 parse_peer_options_v1(int call_type, xmlNode * request,
620 gboolean * local_notify, gboolean * needs_reply, gboolean * process,
621 gboolean * needs_forward)
622 {
623 const char *op = NULL;
624 const char *host = NULL;
625 const char *delegated = NULL;
626 const char *originator = crm_element_value(request, F_ORIG);
627 const char *reply_to = crm_element_value(request, F_CIB_ISREPLY);
628 const char *update = crm_element_value(request, F_CIB_GLOBAL_UPDATE);
629
630 gboolean is_reply = safe_str_eq(reply_to, cib_our_uname);
631
632 if (crm_is_true(update)) {
633 *needs_reply = FALSE;
634 if (is_reply) {
635 *local_notify = TRUE;
636 crm_trace("Processing global/peer update from %s"
637 " that originated from us", originator);
638 } else {
639 crm_trace("Processing global/peer update from %s", originator);
640 }
641 return TRUE;
642 }
643
644 crm_trace("Processing %s request sent by %s", op, originator);
645 op = crm_element_value(request, F_CIB_OPERATION);
646 if (safe_str_eq(op, "cib_shutdown_req")) {
647
648 *local_notify = FALSE;
649 if (reply_to == NULL || is_reply) {
650 *process = TRUE;
651 }
652 if (is_reply) {
653 *needs_reply = FALSE;
654 }
655 return *process;
656 }
657
658 if (is_reply && safe_str_eq(op, CRM_OP_PING)) {
659 process_ping_reply(request);
660 return FALSE;
661 }
662
663 if (is_reply) {
664 crm_trace("Forward reply sent from %s to local clients", originator);
665 *process = FALSE;
666 *needs_reply = FALSE;
667 *local_notify = TRUE;
668 return TRUE;
669 }
670
671 host = crm_element_value(request, F_CIB_HOST);
672 if (host != NULL && safe_str_eq(host, cib_our_uname)) {
673 crm_trace("Processing %s request sent to us from %s", op, originator);
674 return TRUE;
675
676 } else if(is_reply == FALSE && safe_str_eq(op, CRM_OP_PING)) {
677 crm_trace("Processing %s request sent to %s by %s", op, host?host:"everyone", originator);
678 *needs_reply = TRUE;
679 return TRUE;
680
681 } else if (host == NULL && cib_is_master == TRUE) {
682 crm_trace("Processing %s request sent to master instance from %s", op, originator);
683 return TRUE;
684 }
685
686 delegated = crm_element_value(request, F_CIB_DELEGATED);
687 if (delegated != NULL) {
688 crm_trace("Ignoring msg for master instance");
689
690 } else if (host != NULL) {
691
692 crm_trace("Ignoring msg for instance on %s", crm_str(host));
693
694 } else if (reply_to == NULL && cib_is_master == FALSE) {
695
696 crm_trace("Ignoring reply to %s", crm_str(reply_to));
697
698 } else if (safe_str_eq(op, "cib_shutdown_req")) {
699 if (reply_to != NULL) {
700 crm_debug("Processing %s from %s", op, host);
701 *needs_reply = FALSE;
702
703 } else {
704 crm_debug("Processing %s reply from %s", op, host);
705 }
706 return TRUE;
707
708 } else {
709 crm_err("Nothing for us to do?");
710 crm_log_xml_err(request, "Peer[inbound]");
711 }
712
713 return FALSE;
714 }
715
716 static gboolean
717 parse_peer_options_v2(int call_type, xmlNode * request,
718 gboolean * local_notify, gboolean * needs_reply, gboolean * process,
719 gboolean * needs_forward)
720 {
721 const char *host = NULL;
722 const char *delegated = crm_element_value(request, F_CIB_DELEGATED);
723 const char *op = crm_element_value(request, F_CIB_OPERATION);
724 const char *originator = crm_element_value(request, F_ORIG);
725 const char *reply_to = crm_element_value(request, F_CIB_ISREPLY);
726 const char *update = crm_element_value(request, F_CIB_GLOBAL_UPDATE);
727
728 gboolean is_reply = safe_str_eq(reply_to, cib_our_uname);
729
730 if(safe_str_eq(op, CIB_OP_REPLACE)) {
731
732 if (reply_to) {
733 delegated = reply_to;
734 }
735 goto skip_is_reply;
736
737 } else if(safe_str_eq(op, CIB_OP_SYNC)) {
738
739 } else if (is_reply && safe_str_eq(op, CRM_OP_PING)) {
740 process_ping_reply(request);
741 return FALSE;
742
743 } else if (safe_str_eq(op, CIB_OP_UPGRADE)) {
744
745
746
747
748
749
750
751
752
753
754 const char *max = crm_element_value(request, F_CIB_SCHEMA_MAX);
755
756 crm_trace("Parsing %s operation%s for %s with max=%s",
757 op, is_reply?" reply":"", cib_is_master?"master":"slave", max);
758 if(max == NULL && cib_is_master) {
759
760 goto skip_is_reply;
761
762 } else if(max) {
763
764 goto skip_is_reply;
765
766 } else {
767 return FALSE;
768 }
769
770 } else if (crm_is_true(update)) {
771 crm_info("Detected legacy %s global update from %s", op, originator);
772 send_sync_request(NULL);
773 legacy_mode = TRUE;
774 return FALSE;
775
776 } else if (is_reply && cib_op_modifies(call_type)) {
777 crm_trace("Ignoring legacy %s reply sent from %s to local clients", op, originator);
778 return FALSE;
779
780 } else if (safe_str_eq(op, "cib_shutdown_req")) {
781
782 crm_debug("Legacy handling of %s message from %s", op, originator);
783 *local_notify = FALSE;
784 if (reply_to == NULL) {
785 *process = TRUE;
786 }
787 return *process;
788 }
789
790 if(is_reply) {
791 crm_trace("Handling %s reply sent from %s to local clients", op, originator);
792 *process = FALSE;
793 *needs_reply = FALSE;
794 *local_notify = TRUE;
795 return TRUE;
796 }
797
798 skip_is_reply:
799 *process = TRUE;
800 *needs_reply = FALSE;
801
802 if(safe_str_eq(delegated, cib_our_uname)) {
803 *local_notify = TRUE;
804 } else {
805 *local_notify = FALSE;
806 }
807
808 host = crm_element_value(request, F_CIB_HOST);
809 if (host != NULL && safe_str_eq(host, cib_our_uname)) {
810 crm_trace("Processing %s request sent to us from %s", op, originator);
811 *needs_reply = TRUE;
812 return TRUE;
813
814 } else if (host != NULL) {
815
816 crm_trace("Ignoring %s operation for instance on %s", op, crm_str(host));
817 return FALSE;
818
819 } else if(is_reply == FALSE && safe_str_eq(op, CRM_OP_PING)) {
820 *needs_reply = TRUE;
821 }
822
823 crm_trace("Processing %s request sent to everyone by %s/%s on %s %s", op,
824 crm_element_value(request, F_CIB_CLIENTNAME),
825 crm_element_value(request, F_CIB_CALLID),
826 originator, (*local_notify)?"(notify)":"");
827 return TRUE;
828 }
829
830 static gboolean
831 parse_peer_options(int call_type, xmlNode * request,
832 gboolean * local_notify, gboolean * needs_reply, gboolean * process,
833 gboolean * needs_forward)
834 {
835
836
837
838
839 if(cib_legacy_mode()) {
840 return parse_peer_options_v1(
841 call_type, request, local_notify, needs_reply, process, needs_forward);
842 } else {
843 return parse_peer_options_v2(
844 call_type, request, local_notify, needs_reply, process, needs_forward);
845 }
846 }
847
848 static void
849 forward_request(xmlNode * request, crm_client_t * cib_client, int call_options)
850 {
851 const char *op = crm_element_value(request, F_CIB_OPERATION);
852 const char *host = crm_element_value(request, F_CIB_HOST);
853
854 crm_xml_add(request, F_CIB_DELEGATED, cib_our_uname);
855
856 if (host != NULL) {
857 crm_trace("Forwarding %s op to %s", op, host);
858 send_cluster_message(crm_get_peer(0, host), crm_msg_cib, request, FALSE);
859
860 } else {
861 crm_trace("Forwarding %s op to master instance", op);
862 send_cluster_message(NULL, crm_msg_cib, request, FALSE);
863 }
864
865
866 xml_remove_prop(request, F_CIB_DELEGATED);
867
868 if (call_options & cib_discard_reply) {
869 crm_trace("Client not interested in reply");
870 }
871 }
872
873 static gboolean
874 send_peer_reply(xmlNode * msg, xmlNode * result_diff, const char *originator, gboolean broadcast)
875 {
876 CRM_ASSERT(msg != NULL);
877
878 if (broadcast) {
879
880
881
882
883 int diff_add_updates = 0;
884 int diff_add_epoch = 0;
885 int diff_add_admin_epoch = 0;
886
887 int diff_del_updates = 0;
888 int diff_del_epoch = 0;
889 int diff_del_admin_epoch = 0;
890
891 const char *digest = NULL;
892 int format = 1;
893
894 CRM_LOG_ASSERT(result_diff != NULL);
895 digest = crm_element_value(result_diff, XML_ATTR_DIGEST);
896 crm_element_value_int(result_diff, "format", &format);
897
898 cib_diff_version_details(result_diff,
899 &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
900 &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
901
902 crm_trace("Sending update diff %d.%d.%d -> %d.%d.%d %s",
903 diff_del_admin_epoch, diff_del_epoch, diff_del_updates,
904 diff_add_admin_epoch, diff_add_epoch, diff_add_updates, digest);
905
906 crm_xml_add(msg, F_CIB_ISREPLY, originator);
907 crm_xml_add(msg, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
908 crm_xml_add(msg, F_CIB_OPERATION, CIB_OP_APPLY_DIFF);
909 crm_xml_add(msg, F_CIB_USER, CRM_DAEMON_USER);
910
911 if (format == 1) {
912 CRM_ASSERT(digest != NULL);
913 }
914
915 add_message_xml(msg, F_CIB_UPDATE_DIFF, result_diff);
916 crm_log_xml_explicit(msg, "copy");
917 return send_cluster_message(NULL, crm_msg_cib, msg, TRUE);
918
919 } else if (originator != NULL) {
920
921 crm_trace("Sending request result to %s only", originator);
922 crm_xml_add(msg, F_CIB_ISREPLY, originator);
923 return send_cluster_message(crm_get_peer(0, originator), crm_msg_cib, msg, FALSE);
924 }
925
926 return FALSE;
927 }
928
929 void
930 cib_process_request(xmlNode * request, gboolean force_synchronous, gboolean privileged,
931 gboolean unused, crm_client_t * cib_client)
932 {
933 int call_type = 0;
934 int call_options = 0;
935
936 gboolean process = TRUE;
937 gboolean is_update = TRUE;
938 gboolean from_peer = TRUE;
939 gboolean needs_reply = TRUE;
940 gboolean local_notify = FALSE;
941 gboolean needs_forward = FALSE;
942 gboolean global_update = crm_is_true(crm_element_value(request, F_CIB_GLOBAL_UPDATE));
943
944 xmlNode *op_reply = NULL;
945 xmlNode *result_diff = NULL;
946
947 int rc = pcmk_ok;
948 const char *op = crm_element_value(request, F_CIB_OPERATION);
949 const char *originator = crm_element_value(request, F_ORIG);
950 const char *host = crm_element_value(request, F_CIB_HOST);
951 const char *target = NULL;
952 const char *call_id = crm_element_value(request, F_CIB_CALLID);
953 const char *client_id = crm_element_value(request, F_CIB_CLIENTID);
954 const char *client_name = crm_element_value(request, F_CIB_CLIENTNAME);
955 const char *reply_to = crm_element_value(request, F_CIB_ISREPLY);
956
957 if (cib_client) {
958 from_peer = FALSE;
959 }
960
961 cib_num_ops++;
962 if (cib_num_ops == 0) {
963 cib_num_fail = 0;
964 cib_num_local = 0;
965 cib_num_updates = 0;
966 crm_info("Stats wrapped around");
967 }
968
969 crm_element_value_int(request, F_CIB_CALLOPTS, &call_options);
970 if (force_synchronous) {
971 call_options |= cib_sync_call;
972 }
973
974 if (host != NULL && strlen(host) == 0) {
975 host = NULL;
976 }
977
978 if (host) {
979 target = host;
980
981 } else if (call_options & cib_scope_local) {
982 target = "local host";
983
984 } else {
985 target = "master";
986 }
987
988 if (from_peer) {
989 crm_trace("Processing peer %s operation from %s/%s on %s intended for %s (reply=%s)",
990 op, client_name, call_id, originator, target, reply_to);
991 } else {
992 crm_xml_add(request, F_ORIG, cib_our_uname);
993 crm_trace("Processing local %s operation from %s/%s intended for %s", op, client_name, call_id, target);
994 }
995
996 rc = cib_get_operation_id(op, &call_type);
997 if (rc != pcmk_ok) {
998
999 crm_err("Pre-processing of command failed: %s", pcmk_strerror(rc));
1000 return;
1001 }
1002
1003 if (from_peer == FALSE) {
1004 parse_local_options(cib_client, call_type, call_options, host, op,
1005 &local_notify, &needs_reply, &process, &needs_forward);
1006
1007 } else if (parse_peer_options(call_type, request, &local_notify,
1008 &needs_reply, &process, &needs_forward) == FALSE) {
1009 return;
1010 }
1011
1012 is_update = cib_op_modifies(call_type);
1013 if (is_update) {
1014 cib_num_updates++;
1015 }
1016
1017 if (call_options & cib_discard_reply) {
1018 needs_reply = is_update;
1019 local_notify = FALSE;
1020 }
1021
1022 if (needs_forward) {
1023 const char *host = crm_element_value(request, F_CIB_HOST);
1024 const char *section = crm_element_value(request, F_CIB_SECTION);
1025 int log_level = LOG_INFO;
1026
1027 if (safe_str_eq(op, CRM_OP_NOOP)) {
1028 log_level = LOG_DEBUG;
1029 }
1030
1031 do_crm_log(log_level,
1032 "Forwarding %s operation for section %s to %s (origin=%s/%s/%s)",
1033 op,
1034 section ? section : "'all'",
1035 host ? host : cib_legacy_mode() ? "master" : "all",
1036 originator ? originator : "local",
1037 client_name, call_id);
1038
1039 forward_request(request, cib_client, call_options);
1040 return;
1041 }
1042
1043 if (cib_status != pcmk_ok) {
1044 const char *call = crm_element_value(request, F_CIB_CALLID);
1045
1046 rc = cib_status;
1047 crm_err("Operation ignored, cluster configuration is invalid."
1048 " Please repair and restart: %s", pcmk_strerror(cib_status));
1049
1050 op_reply = create_xml_node(NULL, "cib-reply");
1051 crm_xml_add(op_reply, F_TYPE, T_CIB);
1052 crm_xml_add(op_reply, F_CIB_OPERATION, op);
1053 crm_xml_add(op_reply, F_CIB_CALLID, call);
1054 crm_xml_add(op_reply, F_CIB_CLIENTID, client_id);
1055 crm_xml_add_int(op_reply, F_CIB_CALLOPTS, call_options);
1056 crm_xml_add_int(op_reply, F_CIB_RC, rc);
1057
1058 crm_trace("Attaching reply output");
1059 add_message_xml(op_reply, F_CIB_CALLDATA, the_cib);
1060
1061 crm_log_xml_explicit(op_reply, "cib:reply");
1062
1063 } else if (process) {
1064 time_t finished = 0;
1065
1066 int now = time(NULL);
1067 int level = LOG_INFO;
1068 const char *section = crm_element_value(request, F_CIB_SECTION);
1069
1070 cib_num_local++;
1071 rc = cib_process_command(request, &op_reply, &result_diff, privileged);
1072
1073 if (is_update == FALSE) {
1074 level = LOG_TRACE;
1075
1076 } else if (global_update) {
1077 switch (rc) {
1078 case pcmk_ok:
1079 level = LOG_INFO;
1080 break;
1081 case -pcmk_err_old_data:
1082 case -pcmk_err_diff_resync:
1083 case -pcmk_err_diff_failed:
1084 level = LOG_TRACE;
1085 break;
1086 default:
1087 level = LOG_ERR;
1088 }
1089
1090 } else if (rc != pcmk_ok && is_update) {
1091 cib_num_fail++;
1092 level = LOG_WARNING;
1093 }
1094
1095 do_crm_log(level,
1096 "Completed %s operation for section %s: %s (rc=%d, origin=%s/%s/%s, version=%s.%s.%s)",
1097 op, section ? section : "'all'", pcmk_strerror(rc), rc,
1098 originator ? originator : "local", client_name, call_id,
1099 the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION_ADMIN) : "0",
1100 the_cib ? crm_element_value(the_cib, XML_ATTR_GENERATION) : "0",
1101 the_cib ? crm_element_value(the_cib, XML_ATTR_NUMUPDATES) : "0");
1102
1103 finished = time(NULL);
1104 if (finished - now > 3) {
1105 crm_trace("%s operation took %lds to complete", op, (long)(finished - now));
1106 crm_write_blackbox(0, NULL);
1107 }
1108
1109 if (op_reply == NULL && (needs_reply || local_notify)) {
1110 crm_err("Unexpected NULL reply to message");
1111 crm_log_xml_err(request, "null reply");
1112 needs_reply = FALSE;
1113 local_notify = FALSE;
1114 }
1115 }
1116
1117
1118 if(is_update && cib_legacy_mode() == FALSE) {
1119 crm_trace("Completed pre-sync update from %s/%s/%s%s",
1120 originator ? originator : "local", client_name, call_id,
1121 local_notify?" with local notification":"");
1122
1123 } else if (needs_reply == FALSE || stand_alone) {
1124
1125
1126
1127 crm_trace("Completed slave update");
1128
1129 } else if (cib_legacy_mode() &&
1130 rc == pcmk_ok && result_diff != NULL && !(call_options & cib_inhibit_bcast)) {
1131 gboolean broadcast = FALSE;
1132
1133 cib_local_bcast_num++;
1134 crm_xml_add_int(request, F_CIB_LOCAL_NOTIFY_ID, cib_local_bcast_num);
1135 broadcast = send_peer_reply(request, result_diff, originator, TRUE);
1136
1137 if (broadcast && client_id && local_notify && op_reply) {
1138
1139
1140
1141
1142 local_notify = FALSE;
1143 crm_trace("Queuing local %ssync notification for %s",
1144 (call_options & cib_sync_call) ? "" : "a-", client_id);
1145
1146 queue_local_notify(op_reply, client_id, (call_options & cib_sync_call), from_peer);
1147 op_reply = NULL;
1148 }
1149
1150 } else if (call_options & cib_discard_reply) {
1151 crm_trace("Caller isn't interested in reply");
1152
1153 } else if (from_peer) {
1154 if (is_update == FALSE || result_diff == NULL) {
1155 crm_trace("Request not broadcast: R/O call");
1156
1157 } else if (call_options & cib_inhibit_bcast) {
1158 crm_trace("Request not broadcast: inhibited");
1159
1160 } else if (rc != pcmk_ok) {
1161 crm_trace("Request not broadcast: call failed: %s", pcmk_strerror(rc));
1162
1163 } else {
1164 crm_trace("Directing reply to %s", originator);
1165 }
1166
1167 send_peer_reply(op_reply, result_diff, originator, FALSE);
1168 }
1169
1170 if (local_notify && client_id) {
1171 crm_trace("Performing local %ssync notification for %s",
1172 (call_options & cib_sync_call) ? "" : "a-", client_id);
1173 if (process == FALSE) {
1174 do_local_notify(request, client_id, call_options & cib_sync_call, from_peer);
1175 } else {
1176 do_local_notify(op_reply, client_id, call_options & cib_sync_call, from_peer);
1177 }
1178 }
1179
1180 free_xml(op_reply);
1181 free_xml(result_diff);
1182
1183 return;
1184 }
1185
1186 int
1187 cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gboolean privileged)
1188 {
1189 xmlNode *input = NULL;
1190 xmlNode *output = NULL;
1191 xmlNode *result_cib = NULL;
1192 xmlNode *current_cib = NULL;
1193
1194 int call_type = 0;
1195 int call_options = 0;
1196
1197 const char *op = NULL;
1198 const char *section = NULL;
1199 const char *call_id = crm_element_value(request, F_CIB_CALLID);
1200
1201 int rc = pcmk_ok;
1202 int rc2 = pcmk_ok;
1203
1204 gboolean send_r_notify = FALSE;
1205 gboolean global_update = FALSE;
1206 gboolean config_changed = FALSE;
1207 gboolean manage_counters = TRUE;
1208
1209 static mainloop_timer_t *digest_timer = NULL;
1210
1211 CRM_ASSERT(cib_status == pcmk_ok);
1212
1213 if(digest_timer == NULL) {
1214 digest_timer = mainloop_timer_add("digester", 5000, FALSE, cib_digester_cb, NULL);
1215 }
1216
1217 *reply = NULL;
1218 *cib_diff = NULL;
1219 current_cib = the_cib;
1220
1221
1222 op = crm_element_value(request, F_CIB_OPERATION);
1223 crm_element_value_int(request, F_CIB_CALLOPTS, &call_options);
1224 rc = cib_get_operation_id(op, &call_type);
1225
1226 if (rc == pcmk_ok && privileged == FALSE) {
1227 rc = cib_op_can_run(call_type, call_options, privileged, global_update);
1228 }
1229
1230 rc2 = cib_op_prepare(call_type, request, &input, §ion);
1231 if (rc == pcmk_ok) {
1232 rc = rc2;
1233 }
1234
1235 if (rc != pcmk_ok) {
1236 crm_trace("Call setup failed: %s", pcmk_strerror(rc));
1237 goto done;
1238
1239 } else if (cib_op_modifies(call_type) == FALSE) {
1240 rc = cib_perform_op(op, call_options, cib_op_func(call_type), TRUE,
1241 section, request, input, FALSE, &config_changed,
1242 current_cib, &result_cib, NULL, &output);
1243
1244 CRM_CHECK(result_cib == NULL, free_xml(result_cib));
1245 goto done;
1246 }
1247
1248
1249 global_update = crm_is_true(crm_element_value(request, F_CIB_GLOBAL_UPDATE));
1250 if (global_update) {
1251
1252 manage_counters = FALSE;
1253 call_options |= cib_force_diff;
1254 crm_trace("Global update detected");
1255
1256 CRM_CHECK(call_type == 3 || call_type == 4, crm_err("Call type: %d", call_type);
1257 crm_log_xml_err(request, "bad op"));
1258 }
1259
1260 if (rc == pcmk_ok) {
1261 ping_modified_since = TRUE;
1262 if (call_options & cib_inhibit_bcast) {
1263
1264 crm_trace("Skipping update: inhibit broadcast");
1265 manage_counters = FALSE;
1266 }
1267
1268 if (is_not_set(call_options, cib_dryrun) && safe_str_eq(section, XML_CIB_TAG_STATUS)) {
1269
1270 call_options |= cib_zero_copy;
1271 } else {
1272 clear_bit(call_options, cib_zero_copy);
1273 }
1274
1275
1276 rc = cib_perform_op(op, call_options, cib_op_func(call_type), FALSE,
1277 section, request, input, manage_counters, &config_changed,
1278 current_cib, &result_cib, cib_diff, &output);
1279
1280 if (manage_counters == FALSE) {
1281 int format = 1;
1282
1283
1284
1285 if (*cib_diff) {
1286 crm_element_value_int(*cib_diff, "format", &format);
1287 }
1288
1289 if (format == 1) {
1290 config_changed = cib_config_changed(NULL, NULL, cib_diff);
1291 }
1292 }
1293
1294
1295
1296
1297 if (crm_str_eq(CIB_OP_REPLACE, op, TRUE)) {
1298 config_changed = TRUE;
1299 }
1300 }
1301
1302 if (rc == pcmk_ok && is_not_set(call_options, cib_dryrun)) {
1303 crm_trace("Activating %s->%s%s%s",
1304 crm_element_value(current_cib, XML_ATTR_NUMUPDATES),
1305 crm_element_value(result_cib, XML_ATTR_NUMUPDATES),
1306 (is_set(call_options, cib_zero_copy)? " zero-copy" : ""),
1307 (config_changed? " changed" : ""));
1308 if(is_not_set(call_options, cib_zero_copy)) {
1309 rc = activateCibXml(result_cib, config_changed, op);
1310 crm_trace("Activated %s (%d)",
1311 crm_element_value(current_cib, XML_ATTR_NUMUPDATES), rc);
1312 }
1313
1314 if (rc == pcmk_ok && cib_internal_config_changed(*cib_diff)) {
1315 cib_read_config(config_hash, result_cib);
1316 }
1317
1318 if (crm_str_eq(CIB_OP_REPLACE, op, TRUE)) {
1319 if (section == NULL) {
1320 send_r_notify = TRUE;
1321
1322 } else if (safe_str_eq(section, XML_TAG_CIB)) {
1323 send_r_notify = TRUE;
1324
1325 } else if (safe_str_eq(section, XML_CIB_TAG_NODES)) {
1326 send_r_notify = TRUE;
1327
1328 } else if (safe_str_eq(section, XML_CIB_TAG_STATUS)) {
1329 send_r_notify = TRUE;
1330 }
1331
1332 } else if (crm_str_eq(CIB_OP_ERASE, op, TRUE)) {
1333 send_r_notify = TRUE;
1334 }
1335
1336 mainloop_timer_stop(digest_timer);
1337 mainloop_timer_start(digest_timer);
1338
1339 } else if (rc == -pcmk_err_schema_validation) {
1340 CRM_ASSERT(is_not_set(call_options, cib_zero_copy));
1341
1342 if (output != NULL) {
1343 crm_log_xml_info(output, "cib:output");
1344 free_xml(output);
1345 }
1346
1347 output = result_cib;
1348
1349 } else {
1350 crm_trace("Not activating %d %d %s", rc, is_set(call_options, cib_dryrun), crm_element_value(result_cib, XML_ATTR_NUMUPDATES));
1351 if(is_not_set(call_options, cib_zero_copy)) {
1352 free_xml(result_cib);
1353 }
1354 }
1355
1356 if ((call_options & (cib_inhibit_notify|cib_dryrun)) == 0) {
1357 const char *client = crm_element_value(request, F_CIB_CLIENTNAME);
1358
1359 crm_trace("Sending notifications %d", is_set(call_options, cib_dryrun));
1360 cib_diff_notify(call_options, client, call_id, op, input, rc, *cib_diff);
1361 }
1362
1363 if (send_r_notify) {
1364 const char *origin = crm_element_value(request, F_ORIG);
1365
1366 cib_replace_notify(origin, the_cib, rc, *cib_diff);
1367 }
1368
1369 xml_log_patchset(LOG_TRACE, "cib:diff", *cib_diff);
1370 done:
1371 if ((call_options & cib_discard_reply) == 0) {
1372 const char *caller = crm_element_value(request, F_CIB_CLIENTID);
1373
1374 *reply = create_xml_node(NULL, "cib-reply");
1375 crm_xml_add(*reply, F_TYPE, T_CIB);
1376 crm_xml_add(*reply, F_CIB_OPERATION, op);
1377 crm_xml_add(*reply, F_CIB_CALLID, call_id);
1378 crm_xml_add(*reply, F_CIB_CLIENTID, caller);
1379 crm_xml_add_int(*reply, F_CIB_CALLOPTS, call_options);
1380 crm_xml_add_int(*reply, F_CIB_RC, rc);
1381
1382 if (output != NULL) {
1383 crm_trace("Attaching reply output");
1384 add_message_xml(*reply, F_CIB_CALLDATA, output);
1385 }
1386
1387 crm_log_xml_explicit(*reply, "cib:reply");
1388 }
1389
1390 crm_trace("cleanup");
1391
1392 if (cib_op_modifies(call_type) == FALSE && output != current_cib) {
1393 free_xml(output);
1394 output = NULL;
1395 }
1396
1397 if (call_type >= 0) {
1398 cib_op_cleanup(call_type, call_options, &input, &output);
1399 }
1400
1401 crm_trace("done");
1402 return rc;
1403 }
1404
1405 gint
1406 cib_GCompareFunc(gconstpointer a, gconstpointer b)
1407 {
1408 const xmlNode *a_msg = a;
1409 const xmlNode *b_msg = b;
1410
1411 int msg_a_id = 0;
1412 int msg_b_id = 0;
1413 const char *value = NULL;
1414
1415 value = crm_element_value_const(a_msg, F_CIB_CALLID);
1416 msg_a_id = crm_parse_int(value, NULL);
1417
1418 value = crm_element_value_const(b_msg, F_CIB_CALLID);
1419 msg_b_id = crm_parse_int(value, NULL);
1420
1421 if (msg_a_id == msg_b_id) {
1422 return 0;
1423 } else if (msg_a_id < msg_b_id) {
1424 return -1;
1425 }
1426 return 1;
1427 }
1428
1429 #if SUPPORT_HEARTBEAT
1430 void
1431 cib_ha_peer_callback(HA_Message * msg, void *private_data)
1432 {
1433 xmlNode *xml = convert_ha_message(NULL, msg, __FUNCTION__);
1434
1435 cib_peer_callback(xml, private_data);
1436 free_xml(xml);
1437 }
1438 #endif
1439
1440 void
1441 cib_peer_callback(xmlNode * msg, void *private_data)
1442 {
1443 const char *reason = NULL;
1444 const char *originator = crm_element_value(msg, F_ORIG);
1445
1446 if (cib_legacy_mode() && (originator == NULL || crm_str_eq(originator, cib_our_uname, TRUE))) {
1447
1448 int bcast_id = 0;
1449
1450 if (!(crm_element_value_int(msg, F_CIB_LOCAL_NOTIFY_ID, &bcast_id))) {
1451 check_local_notify(bcast_id);
1452 }
1453 return;
1454
1455 } else if (crm_peer_cache == NULL) {
1456 reason = "membership not established";
1457 goto bail;
1458 }
1459
1460 if (crm_element_value(msg, F_CIB_CLIENTNAME) == NULL) {
1461 crm_xml_add(msg, F_CIB_CLIENTNAME, originator);
1462 }
1463
1464
1465 cib_process_request(msg, FALSE, TRUE, TRUE, NULL);
1466 return;
1467
1468 bail:
1469 if (reason) {
1470 const char *seq = crm_element_value(msg, F_SEQ);
1471 const char *op = crm_element_value(msg, F_CIB_OPERATION);
1472
1473 crm_warn("Discarding %s message (%s) from %s: %s", op, seq, originator, reason);
1474 }
1475 }
1476
1477 #if SUPPORT_HEARTBEAT
1478 extern oc_ev_t *cib_ev_token;
1479 static void *ccm_library = NULL;
1480 int (*ccm_api_callback_done) (void *cookie) = NULL;
1481 int (*ccm_api_handle_event) (const oc_ev_t * token) = NULL;
1482
1483 void
1484 cib_client_status_callback(const char *node, const char *client, const char *status, void *private)
1485 {
1486
1487 crm_node_t *peer = NULL;
1488
1489 if (safe_str_eq(client, CRM_SYSTEM_CIB)) {
1490 peer = crm_get_peer(0, node);
1491 if (safe_str_neq(peer->state, CRM_NODE_MEMBER)) {
1492 crm_warn("This peer is not a ccm member (yet). "
1493 "Status ignored: Client %s/%s announced status [%s]",
1494 node, client, status);
1495 return;
1496 }
1497
1498 crm_info("Status update: Client %s/%s now has status [%s]", node, client, status);
1499
1500 if (safe_str_eq(status, JOINSTATUS)) {
1501 status = ONLINESTATUS;
1502
1503 } else if (safe_str_eq(status, LEAVESTATUS)) {
1504 status = OFFLINESTATUS;
1505 }
1506
1507 crm_update_peer_proc(__FUNCTION__, peer, crm_proc_cib, status);
1508 }
1509 return;
1510 }
1511
1512 int
1513 cib_ccm_dispatch(gpointer user_data)
1514 {
1515 int rc = 0;
1516 oc_ev_t *ccm_token = (oc_ev_t *) user_data;
1517
1518 crm_trace("received callback");
1519
1520 if (ccm_api_handle_event == NULL) {
1521 ccm_api_handle_event =
1522 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_handle_event", 1);
1523 }
1524
1525 rc = (*ccm_api_handle_event) (ccm_token);
1526 if (0 == rc) {
1527 return 0;
1528 }
1529
1530 crm_err("CCM connection appears to have failed: rc=%d.", rc);
1531
1532
1533 crm_err("Exiting to recover from CCM connection failure");
1534 return crm_exit(ENOTCONN);
1535 }
1536
1537 int current_instance = 0;
1538 void
1539 cib_ccm_msg_callback(oc_ed_t event, void *cookie, size_t size, const void *data)
1540 {
1541 gboolean update_id = FALSE;
1542 const oc_ev_membership_t *membership = data;
1543
1544 CRM_ASSERT(membership != NULL);
1545
1546 crm_info("Processing CCM event=%s (id=%d)", ccm_event_name(event), membership->m_instance);
1547
1548 if (current_instance > membership->m_instance) {
1549 crm_err("Membership instance ID went backwards! %d->%d",
1550 current_instance, membership->m_instance);
1551 CRM_ASSERT(current_instance <= membership->m_instance);
1552 }
1553
1554 switch (event) {
1555 case OC_EV_MS_NEW_MEMBERSHIP:
1556 case OC_EV_MS_INVALID:
1557 update_id = TRUE;
1558 break;
1559 case OC_EV_MS_PRIMARY_RESTORED:
1560 update_id = TRUE;
1561 break;
1562 case OC_EV_MS_NOT_PRIMARY:
1563 crm_trace("Ignoring transitional CCM event: %s", ccm_event_name(event));
1564 break;
1565 case OC_EV_MS_EVICTED:
1566 crm_err("Evicted from CCM: %s", ccm_event_name(event));
1567 break;
1568 default:
1569 crm_err("Unknown CCM event: %d", event);
1570 }
1571
1572 if (update_id) {
1573 unsigned int lpc = 0;
1574
1575 CRM_CHECK(membership != NULL, return);
1576
1577 current_instance = membership->m_instance;
1578
1579 for (lpc = 0; lpc < membership->m_n_out; lpc++) {
1580 crm_update_ccm_node(membership, lpc + membership->m_out_idx, CRM_NODE_LOST,
1581 current_instance);
1582 }
1583
1584 for (lpc = 0; lpc < membership->m_n_member; lpc++) {
1585 crm_update_ccm_node(membership, lpc + membership->m_memb_idx, CRM_NODE_MEMBER,
1586 current_instance);
1587 }
1588 heartbeat_cluster->llc_ops->client_status(heartbeat_cluster, NULL, crm_system_name, 0);
1589 }
1590
1591 if (ccm_api_callback_done == NULL) {
1592 ccm_api_callback_done =
1593 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_callback_done", 1);
1594 }
1595 (*ccm_api_callback_done) (cookie);
1596 return;
1597 }
1598 #endif
1599
1600 gboolean
1601 can_write(int flags)
1602 {
1603 return TRUE;
1604 }
1605
1606 static gboolean
1607 cib_force_exit(gpointer data)
1608 {
1609 crm_notice("Forcing exit!");
1610 terminate_cib(__FUNCTION__, -1);
1611 return FALSE;
1612 }
1613
1614 static void
1615 disconnect_remote_client(gpointer key, gpointer value, gpointer user_data)
1616 {
1617 crm_client_t *a_client = value;
1618
1619 crm_err("Disconnecting %s... Not implemented", crm_str(a_client->name));
1620 }
1621
1622 void
1623 cib_shutdown(int nsig)
1624 {
1625 struct qb_ipcs_stats srv_stats;
1626
1627 if (cib_shutdown_flag == FALSE) {
1628 int disconnects = 0;
1629 qb_ipcs_connection_t *c = NULL;
1630
1631 cib_shutdown_flag = TRUE;
1632
1633 c = qb_ipcs_connection_first_get(ipcs_rw);
1634 while (c != NULL) {
1635 qb_ipcs_connection_t *last = c;
1636
1637 c = qb_ipcs_connection_next_get(ipcs_rw, last);
1638
1639 crm_debug("Disconnecting r/w client %p...", last);
1640 qb_ipcs_disconnect(last);
1641 qb_ipcs_connection_unref(last);
1642 disconnects++;
1643 }
1644
1645 c = qb_ipcs_connection_first_get(ipcs_ro);
1646 while (c != NULL) {
1647 qb_ipcs_connection_t *last = c;
1648
1649 c = qb_ipcs_connection_next_get(ipcs_ro, last);
1650
1651 crm_debug("Disconnecting r/o client %p...", last);
1652 qb_ipcs_disconnect(last);
1653 qb_ipcs_connection_unref(last);
1654 disconnects++;
1655 }
1656
1657 c = qb_ipcs_connection_first_get(ipcs_shm);
1658 while (c != NULL) {
1659 qb_ipcs_connection_t *last = c;
1660
1661 c = qb_ipcs_connection_next_get(ipcs_shm, last);
1662
1663 crm_debug("Disconnecting non-blocking r/w client %p...", last);
1664 qb_ipcs_disconnect(last);
1665 qb_ipcs_connection_unref(last);
1666 disconnects++;
1667 }
1668
1669 disconnects += crm_hash_table_size(client_connections);
1670
1671 crm_debug("Disconnecting %d remote clients", crm_hash_table_size(client_connections));
1672 g_hash_table_foreach(client_connections, disconnect_remote_client, NULL);
1673 crm_info("Disconnected %d clients", disconnects);
1674 }
1675
1676 qb_ipcs_stats_get(ipcs_rw, &srv_stats, QB_FALSE);
1677
1678 if (crm_hash_table_size(client_connections) == 0) {
1679 crm_info("All clients disconnected (%d)", srv_stats.active_connections);
1680 initiate_exit();
1681
1682 } else {
1683 crm_info("Waiting on %d clients to disconnect (%d)",
1684 crm_hash_table_size(client_connections), srv_stats.active_connections);
1685 }
1686 }
1687
1688 void
1689 initiate_exit(void)
1690 {
1691 int active = 0;
1692 xmlNode *leaving = NULL;
1693
1694 active = crm_active_peers();
1695 if (active < 2) {
1696 terminate_cib(__FUNCTION__, 0);
1697 return;
1698 }
1699
1700 crm_info("Sending disconnect notification to %d peers...", active);
1701
1702 leaving = create_xml_node(NULL, "exit-notification");
1703 crm_xml_add(leaving, F_TYPE, "cib");
1704 crm_xml_add(leaving, F_CIB_OPERATION, "cib_shutdown_req");
1705
1706 send_cluster_message(NULL, crm_msg_cib, leaving, TRUE);
1707 free_xml(leaving);
1708
1709 g_timeout_add(crm_get_msec("5s"), cib_force_exit, NULL);
1710 }
1711
1712 extern int remote_fd;
1713 extern int remote_tls_fd;
1714
1715
1716
1717
1718
1719
1720
1721
1722 void
1723 terminate_cib(const char *caller, int fast)
1724 {
1725 crm_info("%s: Exiting%s...", caller,
1726 (fast < 0)? " fast" : mainloop ? " from mainloop" : "");
1727
1728 if (remote_fd > 0) {
1729 close(remote_fd);
1730 remote_fd = 0;
1731 }
1732 if (remote_tls_fd > 0) {
1733 close(remote_tls_fd);
1734 remote_tls_fd = 0;
1735 }
1736
1737 uninitializeCib();
1738
1739 if (fast < 0) {
1740
1741 cib_ipc_servers_destroy(ipcs_ro, ipcs_rw, ipcs_shm);
1742 crm_exit(EINVAL);
1743
1744 } else if ((mainloop != NULL) && g_main_is_running(mainloop)) {
1745
1746
1747
1748
1749
1750 if (fast == 0) {
1751 crm_cluster_disconnect(&crm_cluster);
1752 }
1753 g_main_quit(mainloop);
1754
1755 } else {
1756
1757
1758 crm_cluster_disconnect(&crm_cluster);
1759 cib_ipc_servers_destroy(ipcs_ro, ipcs_rw, ipcs_shm);
1760 crm_exit(pcmk_ok);
1761 }
1762 }