pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
ipc_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#if defined(US_AUTH_PEERCRED_UCRED) || defined(US_AUTH_PEERCRED_SOCKPEERCRED)
13# ifdef US_AUTH_PEERCRED_UCRED
14# ifndef _GNU_SOURCE
15# define _GNU_SOURCE
16# endif
17# endif
18# include <sys/socket.h>
19#elif defined(US_AUTH_GETPEERUCRED)
20# include <ucred.h>
21#endif
22
23#include <stdio.h>
24#include <sys/types.h>
25#include <errno.h>
26#include <bzlib.h>
27
28#include <crm/crm.h> /* indirectly: pcmk_err_generic */
29#include <crm/msg_xml.h>
30#include <crm/common/ipc.h>
32#include "crmcommon_private.h"
33
46int
48{
49 if (api == NULL) {
50 return EINVAL;
51 }
52
53 *api = calloc(1, sizeof(pcmk_ipc_api_t));
54 if (*api == NULL) {
55 return errno;
56 }
57
58 (*api)->server = server;
59 if (pcmk_ipc_name(*api, false) == NULL) {
61 *api = NULL;
62 return EOPNOTSUPP;
63 }
64
65 (*api)->ipc_size_max = 0;
66
67 // Set server methods and max_size (if not default)
68 switch (server) {
69 case pcmk_ipc_attrd:
70 break;
71
72 case pcmk_ipc_based:
73 (*api)->ipc_size_max = 512 * 1024; // 512KB
74 break;
75
77 (*api)->cmds = pcmk__controld_api_methods();
78 break;
79
80 case pcmk_ipc_execd:
81 break;
82
83 case pcmk_ipc_fenced:
84 break;
85
87 (*api)->cmds = pcmk__pacemakerd_api_methods();
88 break;
89
91 (*api)->cmds = pcmk__schedulerd_api_methods();
92 // @TODO max_size could vary by client, maybe take as argument?
93 (*api)->ipc_size_max = 5 * 1024 * 1024; // 5MB
94 break;
95 }
96 if ((*api)->cmds == NULL) {
98 *api = NULL;
99 return ENOMEM;
100 }
101
102 (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false),
103 (*api)->ipc_size_max);
104 if ((*api)->ipc == NULL) {
105 pcmk_free_ipc_api(*api);
106 *api = NULL;
107 return ENOMEM;
108 }
109
110 // If daemon API has its own data to track, allocate it
111 if ((*api)->cmds->new_data != NULL) {
112 if ((*api)->cmds->new_data(*api) != pcmk_rc_ok) {
113 pcmk_free_ipc_api(*api);
114 *api = NULL;
115 return ENOMEM;
116 }
117 }
118 crm_trace("Created %s API IPC object", pcmk_ipc_name(*api, true));
119 return pcmk_rc_ok;
120}
121
122static void
123free_daemon_specific_data(pcmk_ipc_api_t *api)
124{
125 if ((api != NULL) && (api->cmds != NULL)) {
126 if ((api->cmds->free_data != NULL) && (api->api_data != NULL)) {
127 api->cmds->free_data(api->api_data);
128 api->api_data = NULL;
129 }
130 free(api->cmds);
131 api->cmds = NULL;
132 }
133}
134
144void
146 crm_exit_t status, void *event_data)
147{
148 if ((api != NULL) && (api->cb != NULL)) {
149 api->cb(api, event_type, status, event_data, api->user_data);
150 }
151}
152
161static void
162ipc_post_disconnect(gpointer user_data)
163{
164 pcmk_ipc_api_t *api = user_data;
165
166 crm_info("Disconnected from %s IPC API", pcmk_ipc_name(api, true));
167
168 // Perform any daemon-specific handling needed
169 if ((api->cmds != NULL) && (api->cmds->post_disconnect != NULL)) {
170 api->cmds->post_disconnect(api);
171 }
172
173 // Call client's registered event callback
175 NULL);
176
177 /* If this is being called from a running main loop, mainloop_gio_destroy()
178 * will free ipc and mainloop_io immediately after calling this function.
179 * If this is called from a stopped main loop, these will leak, so the best
180 * practice is to close the connection before stopping the main loop.
181 */
182 api->ipc = NULL;
183 api->mainloop_io = NULL;
184
185 if (api->free_on_disconnect) {
186 /* pcmk_free_ipc_api() has already been called, but did not free api
187 * or api->cmds because this function needed them. Do that now.
188 */
189 free_daemon_specific_data(api);
190 crm_trace("Freeing IPC API object after disconnect");
191 free(api);
192 }
193}
194
200void
202{
203 bool free_on_disconnect = false;
204
205 if (api == NULL) {
206 return;
207 }
208 crm_debug("Releasing %s IPC API", pcmk_ipc_name(api, true));
209
210 if (api->ipc != NULL) {
211 if (api->mainloop_io != NULL) {
212 /* We need to keep the api pointer itself around, because it is the
213 * user data for the IPC client destroy callback. That will be
214 * triggered by the pcmk_disconnect_ipc() call below, but it might
215 * happen later in the main loop (if still running).
216 *
217 * This flag tells the destroy callback to free the object. It can't
218 * do that unconditionally, because the application might call this
219 * function after a disconnect that happened by other means.
220 */
221 free_on_disconnect = api->free_on_disconnect = true;
222 }
223 pcmk_disconnect_ipc(api); // Frees api if free_on_disconnect is true
224 }
225 if (!free_on_disconnect) {
226 free_daemon_specific_data(api);
227 crm_trace("Freeing IPC API object");
228 free(api);
229 }
230}
231
241const char *
242pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
243{
244 if (api == NULL) {
245 return for_log? "Pacemaker" : NULL;
246 }
247 switch (api->server) {
248 case pcmk_ipc_attrd:
249 return for_log? "attribute manager" : NULL /* T_ATTRD */;
250
251 case pcmk_ipc_based:
252 return for_log? "CIB manager" : NULL /* PCMK__SERVER_BASED_RW */;
253
255 return for_log? "controller" : CRM_SYSTEM_CRMD;
256
257 case pcmk_ipc_execd:
258 return for_log? "executor" : NULL /* CRM_SYSTEM_LRMD */;
259
260 case pcmk_ipc_fenced:
261 return for_log? "fencer" : NULL /* "stonith-ng" */;
262
264 return for_log? "launcher" : CRM_SYSTEM_MCP;
265
267 return for_log? "scheduler" : CRM_SYSTEM_PENGINE;
268
269 default:
270 return for_log? "Pacemaker" : NULL;
271 }
272}
273
281bool
283{
284 return (api != NULL) && crm_ipc_connected(api->ipc);
285}
286
297static bool
298call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
299{
300 crm_log_xml_trace(message, "ipc-received");
301 if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
302 return api->cmds->dispatch(api, message);
303 }
304
305 return false;
306}
307
323static int
324dispatch_ipc_data(const char *buffer, pcmk_ipc_api_t *api)
325{
326 bool more = false;
327 xmlNode *msg;
328
329 if (buffer == NULL) {
330 crm_warn("Empty message received from %s IPC",
331 pcmk_ipc_name(api, true));
332 return ENOMSG;
333 }
334
335 msg = string2xml(buffer);
336 if (msg == NULL) {
337 crm_warn("Malformed message received from %s IPC",
338 pcmk_ipc_name(api, true));
339 return EPROTO;
340 }
341
342 more = call_api_dispatch(api, msg);
343 free_xml(msg);
344
345 if (more) {
346 return EINPROGRESS;
347 } else {
348 return pcmk_rc_ok;
349 }
350}
351
364static int
365dispatch_ipc_source_data(const char *buffer, ssize_t length, gpointer user_data)
366{
367 pcmk_ipc_api_t *api = user_data;
368
369 CRM_CHECK(api != NULL, return 0);
370 dispatch_ipc_data(buffer, api);
371 return 0;
372}
373
392int
393pcmk_poll_ipc(pcmk_ipc_api_t *api, int timeout_ms)
394{
395 int rc;
396 struct pollfd pollfd = { 0, };
397
398 if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
399 return EINVAL;
400 }
401 pollfd.fd = crm_ipc_get_fd(api->ipc);
402 pollfd.events = POLLIN;
403 rc = poll(&pollfd, 1, timeout_ms);
404 if (rc < 0) {
405 return errno;
406 } else if (rc == 0) {
407 return EAGAIN;
408 }
409 return pcmk_rc_ok;
410}
411
422void
424{
425 if (api == NULL) {
426 return;
427 }
428 while (crm_ipc_ready(api->ipc) > 0) {
429 if (crm_ipc_read(api->ipc) > 0) {
430 dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
431 }
432 }
433}
434
435// \return Standard Pacemaker return code
436static int
437connect_with_main_loop(pcmk_ipc_api_t *api)
438{
439 int rc;
440
441 struct ipc_client_callbacks callbacks = {
442 .dispatch = dispatch_ipc_source_data,
443 .destroy = ipc_post_disconnect,
444 };
445
446 rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
447 &callbacks, &(api->mainloop_io));
448 if (rc != pcmk_rc_ok) {
449 return rc;
450 }
451 crm_debug("Connected to %s IPC (attached to main loop)",
452 pcmk_ipc_name(api, true));
453 /* After this point, api->mainloop_io owns api->ipc, so api->ipc
454 * should not be explicitly freed.
455 */
456 return pcmk_rc_ok;
457}
458
459// \return Standard Pacemaker return code
460static int
461connect_without_main_loop(pcmk_ipc_api_t *api)
462{
463 int rc;
464
465 if (!crm_ipc_connect(api->ipc)) {
466 rc = errno;
467 crm_ipc_close(api->ipc);
468 return rc;
469 }
470 crm_debug("Connected to %s IPC (without main loop)",
471 pcmk_ipc_name(api, true));
472 return pcmk_rc_ok;
473}
474
483int
485{
486 int rc = pcmk_rc_ok;
487
488 if (api == NULL) {
489 crm_err("Cannot connect to uninitialized API object");
490 return EINVAL;
491 }
492
493 if (api->ipc == NULL) {
494 api->ipc = crm_ipc_new(pcmk_ipc_name(api, false),
495 api->ipc_size_max);
496 if (api->ipc == NULL) {
497 crm_err("Failed to re-create IPC API");
498 return ENOMEM;
499 }
500 }
501
502 if (crm_ipc_connected(api->ipc)) {
503 crm_trace("Already connected to %s IPC API", pcmk_ipc_name(api, true));
504 return pcmk_rc_ok;
505 }
506
507 api->dispatch_type = dispatch_type;
508 switch (dispatch_type) {
510 rc = connect_with_main_loop(api);
511 break;
512
515 rc = connect_without_main_loop(api);
516 break;
517 }
518 if (rc != pcmk_rc_ok) {
519 return rc;
520 }
521
522 if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
523 rc = api->cmds->post_connect(api);
524 if (rc != pcmk_rc_ok) {
525 crm_ipc_close(api->ipc);
526 }
527 }
528 return rc;
529}
530
542void
544{
545 if ((api == NULL) || (api->ipc == NULL)) {
546 return;
547 }
548 switch (api->dispatch_type) {
550 {
551 mainloop_io_t *mainloop_io = api->mainloop_io;
552
553 // Make sure no code with access to api can use these again
554 api->mainloop_io = NULL;
555 api->ipc = NULL;
556
557 mainloop_del_ipc_client(mainloop_io);
558 // After this point api might have already been freed
559 }
560 break;
561
564 {
565 crm_ipc_t *ipc = api->ipc;
566
567 // Make sure no code with access to api can use ipc again
568 api->ipc = NULL;
569
570 // This should always be the case already, but to be safe
571 api->free_on_disconnect = false;
572
573 crm_ipc_destroy(ipc);
574 ipc_post_disconnect(api);
575 }
576 break;
577 }
578}
579
592void
594 void *user_data)
595{
596 if (api == NULL) {
597 return;
598 }
599 api->cb = cb;
600 api->user_data = user_data;
601}
602
615int
617{
618 int rc;
619 xmlNode *reply = NULL;
621
622 if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
623 return EINVAL;
624 }
625 crm_log_xml_trace(request, "ipc-sent");
626
627 // Synchronous dispatch requires waiting for a reply
629 && (api->cmds != NULL)
630 && (api->cmds->reply_expected != NULL)
631 && (api->cmds->reply_expected(api, request))) {
633 }
634
635 // The 0 here means a default timeout of 5 seconds
636 rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
637
638 if (rc < 0) {
639 return pcmk_legacy2rc(rc);
640 } else if (rc == 0) {
641 return ENODATA;
642 }
643
644 // With synchronous dispatch, we dispatch any reply now
645 if (reply != NULL) {
646 bool more = call_api_dispatch(api, reply);
647
648 free_xml(reply);
649
650 while (more) {
651 rc = crm_ipc_read(api->ipc);
652
653 if (rc == -EAGAIN) {
654 continue;
655 } else if (rc == -ENOMSG || rc == pcmk_ok) {
656 return pcmk_rc_ok;
657 } else if (rc < 0) {
658 return -rc;
659 }
660
661 rc = dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
662
663 if (rc == pcmk_rc_ok) {
664 more = false;
665 } else if (rc == EINPROGRESS) {
666 more = true;
667 } else {
668 continue;
669 }
670 }
671 }
672 return pcmk_rc_ok;
673}
674
697static xmlNode *
698create_purge_node_request(pcmk_ipc_api_t *api, const char *node_name,
699 uint32_t nodeid)
700{
701 xmlNode *request = NULL;
702 const char *client = crm_system_name? crm_system_name : "client";
703
704 switch (api->server) {
705 case pcmk_ipc_attrd:
706 request = create_xml_node(NULL, __func__);
707 crm_xml_add(request, F_TYPE, T_ATTRD);
710 crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node_name);
711 if (nodeid > 0) {
712 crm_xml_add_int(request, PCMK__XA_ATTR_NODE_ID, (int) nodeid);
713 }
714 break;
715
717 case pcmk_ipc_fenced:
719 request = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL,
720 pcmk_ipc_name(api, false), client, NULL);
721 if (nodeid > 0) {
722 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
723 }
724 crm_xml_add(request, XML_ATTR_UNAME, node_name);
725 break;
726
727 case pcmk_ipc_based:
728 case pcmk_ipc_execd:
730 break;
731 }
732 return request;
733}
734
746int
747pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
748{
749 int rc = 0;
750 xmlNode *request = NULL;
751
752 if (api == NULL) {
753 return EINVAL;
754 }
755 if ((node_name == NULL) && (nodeid == 0)) {
756 return EINVAL;
757 }
758
759 request = create_purge_node_request(api, node_name, nodeid);
760 if (request == NULL) {
761 return EOPNOTSUPP;
762 }
763 rc = pcmk__send_ipc_request(api, request);
764 free_xml(request);
765
766 crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
767 pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
768 return rc;
769}
770
771/*
772 * Generic IPC API (to eventually be deprecated as public API and made internal)
773 */
774
775struct crm_ipc_s {
776 struct pollfd pfd;
777 unsigned int max_buf_size; // maximum bytes we can send or receive over IPC
778 unsigned int buf_size; // size of allocated buffer
779 int msg_size;
780 int need_reply;
781 char *buffer;
782 char *server_name; // server IPC name being connected to
783 qb_ipcc_connection_t *ipc;
784};
785
799crm_ipc_t *
800crm_ipc_new(const char *name, size_t max_size)
801{
802 crm_ipc_t *client = NULL;
803
804 client = calloc(1, sizeof(crm_ipc_t));
805 if (client == NULL) {
806 crm_err("Could not create IPC connection: %s", strerror(errno));
807 return NULL;
808 }
809
810 client->server_name = strdup(name);
811 if (client->server_name == NULL) {
812 crm_err("Could not create %s IPC connection: %s",
813 name, strerror(errno));
814 free(client);
815 return NULL;
816 }
817 client->buf_size = pcmk__ipc_buffer_size(max_size);
818 client->buffer = malloc(client->buf_size);
819 if (client->buffer == NULL) {
820 crm_err("Could not create %s IPC connection: %s",
821 name, strerror(errno));
822 free(client->server_name);
823 free(client);
824 return NULL;
825 }
826
827 /* Clients initiating connection pick the max buf size */
828 client->max_buf_size = client->buf_size;
829
830 client->pfd.fd = -1;
831 client->pfd.events = POLLIN;
832 client->pfd.revents = 0;
833
834 return client;
835}
836
846bool
848{
849 uid_t cl_uid = 0;
850 gid_t cl_gid = 0;
851 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
852 int rv;
853
854 client->need_reply = FALSE;
855 client->ipc = qb_ipcc_connect(client->server_name, client->buf_size);
856
857 if (client->ipc == NULL) {
858 crm_debug("Could not establish %s IPC connection: %s (%d)",
859 client->server_name, pcmk_rc_str(errno), errno);
860 return FALSE;
861 }
862
863 client->pfd.fd = crm_ipc_get_fd(client);
864 if (client->pfd.fd < 0) {
865 rv = errno;
866 /* message already omitted */
867 crm_ipc_close(client);
868 errno = rv;
869 return FALSE;
870 }
871
872 rv = pcmk_daemon_user(&cl_uid, &cl_gid);
873 if (rv < 0) {
874 /* message already omitted */
875 crm_ipc_close(client);
876 errno = -rv;
877 return FALSE;
878 }
879
880 if ((rv = pcmk__crm_ipc_is_authentic_process(client->ipc, client->pfd.fd, cl_uid, cl_gid,
881 &found_pid, &found_uid,
882 &found_gid)) == pcmk_rc_ipc_unauthorized) {
883 crm_err("%s IPC provider authentication failed: process %lld has "
884 "uid %lld (expected %lld) and gid %lld (expected %lld)",
885 client->server_name,
886 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
887 (long long) found_uid, (long long) cl_uid,
888 (long long) found_gid, (long long) cl_gid);
889 crm_ipc_close(client);
890 errno = ECONNABORTED;
891 return FALSE;
892
893 } else if (rv != pcmk_rc_ok) {
894 crm_perror(LOG_ERR, "Could not verify authenticity of %s IPC provider",
895 client->server_name);
896 crm_ipc_close(client);
897 if (rv > 0) {
898 errno = rv;
899 } else {
900 errno = ENOTCONN;
901 }
902 return FALSE;
903 }
904
905 qb_ipcc_context_set(client->ipc, client);
906
907 client->max_buf_size = qb_ipcc_get_buffer_size(client->ipc);
908 if (client->max_buf_size > client->buf_size) {
909 free(client->buffer);
910 client->buffer = calloc(1, client->max_buf_size);
911 client->buf_size = client->max_buf_size;
912 }
913 return TRUE;
914}
915
916void
918{
919 if (client) {
920 if (client->ipc) {
921 qb_ipcc_connection_t *ipc = client->ipc;
922
923 client->ipc = NULL;
924 qb_ipcc_disconnect(ipc);
925 }
926 }
927}
928
929void
931{
932 if (client) {
933 if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
934 crm_notice("Destroying active %s IPC connection",
935 client->server_name);
936 /* The next line is basically unsafe
937 *
938 * If this connection was attached to mainloop and mainloop is active,
939 * the 'disconnected' callback will end up back here and we'll end
940 * up free'ing the memory twice - something that can still happen
941 * even without this if we destroy a connection and it closes before
942 * we call exit
943 */
944 /* crm_ipc_close(client); */
945 } else {
946 crm_trace("Destroying inactive %s IPC connection",
947 client->server_name);
948 }
949 free(client->buffer);
950 free(client->server_name);
951 free(client);
952 }
953}
954
955int
957{
958 int fd = 0;
959
960 if (client && client->ipc && (qb_ipcc_fd_get(client->ipc, &fd) == 0)) {
961 return fd;
962 }
963 errno = EINVAL;
964 crm_perror(LOG_ERR, "Could not obtain file descriptor for %s IPC",
965 (client? client->server_name : "unspecified"));
966 return -errno;
967}
968
969bool
971{
972 bool rc = FALSE;
973
974 if (client == NULL) {
975 crm_trace("No client");
976 return FALSE;
977
978 } else if (client->ipc == NULL) {
979 crm_trace("No connection");
980 return FALSE;
981
982 } else if (client->pfd.fd < 0) {
983 crm_trace("Bad descriptor");
984 return FALSE;
985 }
986
987 rc = qb_ipcc_is_connected(client->ipc);
988 if (rc == FALSE) {
989 client->pfd.fd = -EINVAL;
990 }
991 return rc;
992}
993
1001int
1003{
1004 int rc;
1005
1006 CRM_ASSERT(client != NULL);
1007
1008 if (crm_ipc_connected(client) == FALSE) {
1009 return -ENOTCONN;
1010 }
1011
1012 client->pfd.revents = 0;
1013 rc = poll(&(client->pfd), 1, 0);
1014 return (rc < 0)? -errno : rc;
1015}
1016
1017// \return Standard Pacemaker return code
1018static int
1019crm_ipc_decompress(crm_ipc_t * client)
1020{
1021 pcmk__ipc_header_t *header = (pcmk__ipc_header_t *)(void*)client->buffer;
1022
1023 if (header->size_compressed) {
1024 int rc = 0;
1025 unsigned int size_u = 1 + header->size_uncompressed;
1026 /* never let buf size fall below our max size required for ipc reads. */
1027 unsigned int new_buf_size = QB_MAX((sizeof(pcmk__ipc_header_t) + size_u), client->max_buf_size);
1028 char *uncompressed = calloc(1, new_buf_size);
1029
1030 crm_trace("Decompressing message data %u bytes into %u bytes",
1031 header->size_compressed, size_u);
1032
1033 rc = BZ2_bzBuffToBuffDecompress(uncompressed + sizeof(pcmk__ipc_header_t), &size_u,
1034 client->buffer + sizeof(pcmk__ipc_header_t), header->size_compressed, 1, 0);
1035
1036 if (rc != BZ_OK) {
1037 crm_err("Decompression failed: %s " CRM_XS " bzerror=%d",
1038 bz2_strerror(rc), rc);
1039 free(uncompressed);
1040 return EILSEQ;
1041 }
1042
1043 /*
1044 * This assert no longer holds true. For an identical msg, some clients may
1045 * require compression, and others may not. If that same msg (event) is sent
1046 * to multiple clients, it could result in some clients receiving a compressed
1047 * msg even though compression was not explicitly required for them.
1048 *
1049 * CRM_ASSERT((header->size_uncompressed + sizeof(pcmk__ipc_header_t)) >= ipc_buffer_max);
1050 */
1051 CRM_ASSERT(size_u == header->size_uncompressed);
1052
1053 memcpy(uncompressed, client->buffer, sizeof(pcmk__ipc_header_t)); /* Preserve the header */
1054 header = (pcmk__ipc_header_t *)(void*)uncompressed;
1055
1056 free(client->buffer);
1057 client->buf_size = new_buf_size;
1058 client->buffer = uncompressed;
1059 }
1060
1061 CRM_ASSERT(client->buffer[sizeof(pcmk__ipc_header_t) + header->size_uncompressed - 1] == 0);
1062 return pcmk_rc_ok;
1063}
1064
1065long
1067{
1068 pcmk__ipc_header_t *header = NULL;
1069
1070 CRM_ASSERT(client != NULL);
1071 CRM_ASSERT(client->ipc != NULL);
1072 CRM_ASSERT(client->buffer != NULL);
1073
1074 client->buffer[0] = 0;
1075 client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1076 client->buf_size, 0);
1077 if (client->msg_size >= 0) {
1078 int rc = crm_ipc_decompress(client);
1079
1080 if (rc != pcmk_rc_ok) {
1081 return pcmk_rc2legacy(rc);
1082 }
1083
1084 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1085 if (!pcmk__valid_ipc_header(header)) {
1086 return -EBADMSG;
1087 }
1088
1089 crm_trace("Received %s IPC event %d size=%u rc=%d text='%.100s'",
1090 client->server_name, header->qb.id, header->qb.size,
1091 client->msg_size,
1092 client->buffer + sizeof(pcmk__ipc_header_t));
1093
1094 } else {
1095 crm_trace("No message received from %s IPC: %s",
1096 client->server_name, pcmk_strerror(client->msg_size));
1097
1098 if (client->msg_size == -EAGAIN) {
1099 return -EAGAIN;
1100 }
1101 }
1102
1103 if (crm_ipc_connected(client) == FALSE || client->msg_size == -ENOTCONN) {
1104 crm_err("Connection to %s IPC failed", client->server_name);
1105 }
1106
1107 if (header) {
1108 /* Data excluding the header */
1109 return header->size_uncompressed;
1110 }
1111 return -ENOMSG;
1112}
1113
1114const char *
1116{
1117 CRM_ASSERT(client != NULL);
1118 return client->buffer + sizeof(pcmk__ipc_header_t);
1119}
1120
1121uint32_t
1123{
1124 pcmk__ipc_header_t *header = NULL;
1125
1126 CRM_ASSERT(client != NULL);
1127 if (client->buffer == NULL) {
1128 return 0;
1129 }
1130
1131 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1132 return header->flags;
1133}
1134
1135const char *
1137{
1138 CRM_ASSERT(client != NULL);
1139 return client->server_name;
1140}
1141
1142// \return Standard Pacemaker return code
1143static int
1144internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
1145 ssize_t *bytes)
1146{
1147 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1148 int rc = pcmk_rc_ok;
1149
1150 /* get the reply */
1151 crm_trace("Waiting on reply to %s IPC message %d",
1152 client->server_name, request_id);
1153 do {
1154
1155 *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1156 if (*bytes > 0) {
1157 pcmk__ipc_header_t *hdr = NULL;
1158
1159 rc = crm_ipc_decompress(client);
1160 if (rc != pcmk_rc_ok) {
1161 return rc;
1162 }
1163
1164 hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1165 if (hdr->qb.id == request_id) {
1166 /* Got it */
1167 break;
1168 } else if (hdr->qb.id < request_id) {
1169 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1170
1171 crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1172 crm_log_xml_notice(bad, "OldIpcReply");
1173
1174 } else {
1175 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1176
1177 crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1178 crm_log_xml_notice(bad, "ImpossibleReply");
1179 CRM_ASSERT(hdr->qb.id <= request_id);
1180 }
1181 } else if (crm_ipc_connected(client) == FALSE) {
1182 crm_err("%s IPC provider disconnected while waiting for message %d",
1183 client->server_name, request_id);
1184 break;
1185 }
1186
1187 } while (time(NULL) < timeout);
1188
1189 if (*bytes < 0) {
1190 rc = (int) -*bytes; // System errno
1191 }
1192 return rc;
1193}
1194
1208int
1209crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, int32_t ms_timeout,
1210 xmlNode ** reply)
1211{
1212 int rc = 0;
1213 ssize_t qb_rc = 0;
1214 ssize_t bytes = 0;
1215 struct iovec *iov;
1216 static uint32_t id = 0;
1217 static int factor = 8;
1218 pcmk__ipc_header_t *header;
1219
1220 if (client == NULL) {
1221 crm_notice("Can't send IPC request without connection (bug?): %.100s",
1222 message);
1223 return -ENOTCONN;
1224
1225 } else if (crm_ipc_connected(client) == FALSE) {
1226 /* Don't even bother */
1227 crm_notice("Can't send %s IPC requests: Connection closed",
1228 client->server_name);
1229 return -ENOTCONN;
1230 }
1231
1232 if (ms_timeout == 0) {
1233 ms_timeout = 5000;
1234 }
1235
1236 if (client->need_reply) {
1237 qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1238 if (qb_rc < 0) {
1239 crm_warn("Sending %s IPC disabled until pending reply received",
1240 client->server_name);
1241 return -EALREADY;
1242
1243 } else {
1244 crm_notice("Sending %s IPC re-enabled after pending reply received",
1245 client->server_name);
1246 client->need_reply = FALSE;
1247 }
1248 }
1249
1250 id++;
1251 CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1252 rc = pcmk__ipc_prepare_iov(id, message, client->max_buf_size, &iov, &bytes);
1253 if (rc != pcmk_rc_ok) {
1254 crm_warn("Couldn't prepare %s IPC request: %s " CRM_XS " rc=%d",
1255 client->server_name, pcmk_rc_str(rc), rc);
1256 return pcmk_rc2legacy(rc);
1257 }
1258
1259 header = iov[0].iov_base;
1260 pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1261
1263 /* Don't look for a synchronous response */
1265 }
1266
1267 if(header->size_compressed) {
1268 if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
1269 crm_notice("Compressed message exceeds %d0%% of configured IPC "
1270 "limit (%u bytes); consider setting PCMK_ipc_buffer to "
1271 "%u or higher",
1272 factor, client->max_buf_size, 2 * client->max_buf_size);
1273 factor++;
1274 }
1275 }
1276
1277 crm_trace("Sending %s IPC request %d of %u bytes using %dms timeout",
1278 client->server_name, header->qb.id, header->qb.size, ms_timeout);
1279
1280 if ((ms_timeout > 0) || !pcmk_is_set(flags, crm_ipc_client_response)) {
1281
1282 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1283
1284 do {
1285 /* @TODO Is this check really needed? Won't qb_ipcc_sendv() return
1286 * an error if it's not connected?
1287 */
1288 if (!crm_ipc_connected(client)) {
1289 goto send_cleanup;
1290 }
1291
1292 qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1293 } while ((qb_rc == -EAGAIN) && (time(NULL) < timeout));
1294
1295 rc = (int) qb_rc; // Negative of system errno, or bytes sent
1296 if (qb_rc <= 0) {
1297 goto send_cleanup;
1298
1300 crm_trace("Not waiting for reply to %s IPC request %d",
1301 client->server_name, header->qb.id);
1302 goto send_cleanup;
1303 }
1304
1305 rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes);
1306 if (rc != pcmk_rc_ok) {
1307 /* We didn't get the reply in time, so disable future sends for now.
1308 * The only alternative would be to close the connection since we
1309 * don't know how to detect and discard out-of-sequence replies.
1310 *
1311 * @TODO Implement out-of-sequence detection
1312 */
1313 client->need_reply = TRUE;
1314 }
1315 rc = (int) bytes; // Negative system errno, or size of reply received
1316
1317 } else {
1318 // No timeout, and client response needed
1319 do {
1320 qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
1321 client->buf_size, -1);
1322 } while ((qb_rc == -EAGAIN) && crm_ipc_connected(client));
1323 rc = (int) qb_rc; // Negative system errno, or size of reply received
1324 }
1325
1326 if (rc > 0) {
1327 pcmk__ipc_header_t *hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1328
1329 crm_trace("Received %d-byte reply %d to %s IPC %d: %.100s",
1330 rc, hdr->qb.id, client->server_name, header->qb.id,
1331 crm_ipc_buffer(client));
1332
1333 if (reply) {
1334 *reply = string2xml(crm_ipc_buffer(client));
1335 }
1336
1337 } else {
1338 crm_trace("No reply to %s IPC %d: rc=%d",
1339 client->server_name, header->qb.id, rc);
1340 }
1341
1342 send_cleanup:
1343 if (crm_ipc_connected(client) == FALSE) {
1344 crm_notice("Couldn't send %s IPC request %d: Connection closed "
1345 CRM_XS " rc=%d", client->server_name, header->qb.id, rc);
1346
1347 } else if (rc == -ETIMEDOUT) {
1348 crm_warn("%s IPC request %d failed: %s after %dms " CRM_XS " rc=%d",
1349 client->server_name, header->qb.id, pcmk_strerror(rc),
1350 ms_timeout, rc);
1351 crm_write_blackbox(0, NULL);
1352
1353 } else if (rc <= 0) {
1354 crm_warn("%s IPC request %d failed: %s " CRM_XS " rc=%d",
1355 client->server_name, header->qb.id,
1356 ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1357 }
1358
1360 return rc;
1361}
1362
1363int
1364pcmk__crm_ipc_is_authentic_process(qb_ipcc_connection_t *qb_ipc, int sock, uid_t refuid, gid_t refgid,
1365 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1366{
1367 int ret = 0;
1368 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1369#if defined(US_AUTH_PEERCRED_UCRED)
1370 struct ucred ucred;
1371 socklen_t ucred_len = sizeof(ucred);
1372#endif
1373
1374#ifdef HAVE_QB_IPCC_AUTH_GET
1375 if (qb_ipc && !qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid)) {
1376 goto do_checks;
1377 }
1378#endif
1379
1380#if defined(US_AUTH_PEERCRED_UCRED)
1381 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1382 &ucred, &ucred_len)
1383 && ucred_len == sizeof(ucred)) {
1384 found_pid = ucred.pid; found_uid = ucred.uid; found_gid = ucred.gid;
1385
1386#elif defined(US_AUTH_PEERCRED_SOCKPEERCRED)
1387 struct sockpeercred sockpeercred;
1388 socklen_t sockpeercred_len = sizeof(sockpeercred);
1389
1390 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1391 &sockpeercred, &sockpeercred_len)
1392 && sockpeercred_len == sizeof(sockpeercred_len)) {
1393 found_pid = sockpeercred.pid;
1394 found_uid = sockpeercred.uid; found_gid = sockpeercred.gid;
1395
1396#elif defined(US_AUTH_GETPEEREID)
1397 if (!getpeereid(sock, &found_uid, &found_gid)) {
1398 found_pid = PCMK__SPECIAL_PID; /* cannot obtain PID (FreeBSD) */
1399
1400#elif defined(US_AUTH_GETPEERUCRED)
1401 ucred_t *ucred;
1402 if (!getpeerucred(sock, &ucred)) {
1403 errno = 0;
1404 found_pid = ucred_getpid(ucred);
1405 found_uid = ucred_geteuid(ucred); found_gid = ucred_getegid(ucred);
1406 ret = -errno;
1407 ucred_free(ucred);
1408 if (ret) {
1409 return (ret < 0) ? ret : -pcmk_err_generic;
1410 }
1411
1412#else
1413# error "No way to authenticate a Unix socket peer"
1414 errno = 0;
1415 if (0) {
1416#endif
1417#ifdef HAVE_QB_IPCC_AUTH_GET
1418 do_checks:
1419#endif
1420 if (gotpid != NULL) {
1421 *gotpid = found_pid;
1422 }
1423 if (gotuid != NULL) {
1424 *gotuid = found_uid;
1425 }
1426 if (gotgid != NULL) {
1427 *gotgid = found_gid;
1428 }
1429 if (found_uid == 0 || found_uid == refuid || found_gid == refgid) {
1430 ret = 0;
1431 } else {
1433 }
1434 } else {
1435 ret = (errno > 0) ? errno : pcmk_rc_error;
1436 }
1437 return ret;
1438}
1439
1440int
1441crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
1442 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1443{
1444 int ret = pcmk__crm_ipc_is_authentic_process(NULL, sock, refuid, refgid,
1445 gotpid, gotuid, gotgid);
1446
1447 /* The old function had some very odd return codes*/
1448 if (ret == 0) {
1449 return 1;
1450 } else if (ret == pcmk_rc_ipc_unauthorized) {
1451 return 0;
1452 } else {
1453 return pcmk_rc2legacy(ret);
1454 }
1455}
1456
1457int
1459 gid_t refgid, pid_t *gotpid)
1460{
1461 static char last_asked_name[PATH_MAX / 2] = ""; /* log spam prevention */
1462 int fd;
1463 int rc = pcmk_rc_ipc_unresponsive;
1464 int auth_rc = 0;
1465 int32_t qb_rc;
1466 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1467 qb_ipcc_connection_t *c;
1468#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1469 struct pollfd pollfd = { 0, };
1470 int poll_rc;
1471
1472 c = qb_ipcc_connect_async(name, 0,
1473 &(pollfd.fd));
1474#else
1475 c = qb_ipcc_connect(name, 0);
1476#endif
1477 if (c == NULL) {
1478 crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1480 goto bail;
1481 }
1482#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1483 pollfd.events = POLLIN;
1484 do {
1485 poll_rc = poll(&pollfd, 1, 2000);
1486 } while ((poll_rc == -1) && (errno == EINTR));
1487 if ((poll_rc <= 0) || (qb_ipcc_connect_continue(c) != 0)) {
1488 crm_info("Could not connect to %s IPC: %s", name,
1489 (poll_rc == 0)?"timeout":strerror(errno));
1491 if (poll_rc > 0) {
1492 c = NULL; // qb_ipcc_connect_continue cleaned up for us
1493 }
1494 goto bail;
1495 }
1496#endif
1497
1498 qb_rc = qb_ipcc_fd_get(c, &fd);
1499 if (qb_rc != 0) {
1500 rc = (int) -qb_rc; // System errno
1501 crm_err("Could not get fd from %s IPC: %s " CRM_XS " rc=%d",
1502 name, pcmk_rc_str(rc), rc);
1503 goto bail;
1504 }
1505
1506 auth_rc = pcmk__crm_ipc_is_authentic_process(c, fd, refuid, refgid, &found_pid,
1507 &found_uid, &found_gid);
1508 if (auth_rc == pcmk_rc_ipc_unauthorized) {
1509 crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1510 " process %lld (uid: %lld, gid: %lld)",
1511 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1512 (long long) found_uid, (long long) found_gid);
1514 goto bail;
1515 }
1516
1517 if (auth_rc != pcmk_rc_ok) {
1518 rc = auth_rc;
1519 crm_err("Could not get peer credentials from %s IPC: %s "
1520 CRM_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1521 goto bail;
1522 }
1523
1524 if (gotpid != NULL) {
1525 *gotpid = found_pid;
1526 }
1527
1528 rc = pcmk_rc_ok;
1529 if ((found_uid != refuid || found_gid != refgid)
1530 && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1531 if ((found_uid == 0) && (refuid != 0)) {
1532 crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1533 " credentials are %lld:%lld, hazard of violating"
1534 " the least privilege principle",
1535 name, (long long) refuid, (long long) refgid);
1536 } else {
1537 crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1538 " expected credentials are %lld:%lld, which may"
1539 " mean a different set of privileges than expected",
1540 name, (long long) found_uid, (long long) found_gid,
1541 (long long) refuid, (long long) refgid);
1542 }
1543 memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1544 }
1545
1546bail:
1547 if (c != NULL) {
1548 qb_ipcc_disconnect(c);
1549 }
1550 return rc;
1551}
const char * name
Definition: cib.c:24
int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, struct ipc_client_callbacks *callbacks, mainloop_io_t **source)
Connect to IPC and add it as a main loop source.
Definition: mainloop.c:894
uint64_t flags
Definition: remote.c:3
int pcmk_daemon_user(uid_t *uid, gid_t *gid)
Get user and group IDs of pacemaker daemon user.
Definition: utils.c:97
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:122
A dumping ground.
#define CRM_SYSTEM_CRMD
Definition: crm.h:106
#define CRM_SYSTEM_MCP
Definition: crm.h:111
#define CRM_OP_RM_NODE_CACHE
Definition: crm.h:159
char * crm_system_name
Definition: utils.c:54
#define CRM_SYSTEM_PENGINE
Definition: crm.h:108
#define PCMK__XA_ATTR_NODE_NAME
Definition: crm_internal.h:68
#define PCMK__ATTRD_CMD_PEER_REMOVE
Definition: crm_internal.h:95
#define PCMK__XA_ATTR_NODE_ID
Definition: crm_internal.h:67
#define PCMK__XA_TASK
Definition: crm_internal.h:80
struct pcmk__ipc_header_s pcmk__ipc_header_t
G_GNUC_INTERNAL unsigned int pcmk__ipc_buffer_size(unsigned int max)
Definition: ipc_common.c:31
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)
G_GNUC_INTERNAL bool pcmk__valid_ipc_header(const pcmk__ipc_header_t *header)
Definition: ipc_common.c:81
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__controld_api_methods(void)
Definition: ipc_controld.c:262
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__schedulerd_api_methods(void)
IPC interface to Pacemaker daemons.
void(* pcmk_ipc_callback_t)(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data, void *user_data)
Callback function type for Pacemaker daemon IPC APIs.
Definition: ipc.h:111
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition: ipc.h:43
crm_ipc_flags
Definition: ipc.h:145
@ crm_ipc_flags_none
Definition: ipc.h:146
@ crm_ipc_client_response
Definition: ipc.h:151
@ crm_ipc_proxied
Definition: ipc.h:150
void pcmk_free_ipc_event(struct iovec *event)
Free an I/O vector created by pcmk__ipc_prepare_iov()
Definition: ipc_server.c:280
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
Definition: ipc.h:80
@ pcmk_ipc_event_disconnect
Termination of IPC connection.
Definition: ipc.h:82
pcmk_ipc_server
Available IPC interfaces.
Definition: ipc.h:69
@ pcmk_ipc_schedulerd
Scheduler.
Definition: ipc.h:76
@ pcmk_ipc_based
CIB manager.
Definition: ipc.h:71
@ pcmk_ipc_execd
Executor.
Definition: ipc.h:73
@ pcmk_ipc_pacemakerd
Launcher.
Definition: ipc.h:75
@ pcmk_ipc_attrd
Attribute manager.
Definition: ipc.h:70
@ pcmk_ipc_controld
Controller.
Definition: ipc.h:72
@ pcmk_ipc_fenced
Fencer.
Definition: ipc.h:74
pcmk_ipc_dispatch
How IPC replies should be dispatched.
Definition: ipc.h:88
@ pcmk_ipc_dispatch_sync
Sending a command will wait for any reply.
Definition: ipc.h:91
@ pcmk_ipc_dispatch_poll
Caller will poll and dispatch IPC.
Definition: ipc.h:90
@ pcmk_ipc_dispatch_main
Attach IPC to GMainLoop for dispatch.
Definition: ipc.h:89
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:163
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:930
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1209
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance.
Definition: ipc_client.c:543
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc_client.c:1136
int pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
Connect to a Pacemaker daemon via IPC.
Definition: ipc_client.c:484
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition: ipc_client.c:616
const char * pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection.
Definition: ipc_client.c:242
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1066
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:956
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1002
void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
Definition: ipc_client.c:145
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:970
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:847
int crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid, pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
Check the authenticity of the IPC socket peer process (legacy)
Definition: ipc_client.c:1441
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:917
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
Definition: ipc_client.c:201
int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid)
Definition: ipc_client.c:1458
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc_client.c:1122
int pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
Create a new object for using Pacemaker daemon IPC.
Definition: ipc_client.c:47
int pcmk__crm_ipc_is_authentic_process(qb_ipcc_connection_t *qb_ipc, int sock, uid_t refuid, gid_t refgid, pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
Check the authenticity of the IPC socket peer process.
Definition: ipc_client.c:1364
int pcmk_poll_ipc(pcmk_ipc_api_t *api, int timeout_ms)
Check whether an IPC connection has data available (without main loop)
Definition: ipc_client.c:393
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1115
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active.
Definition: ipc_client.c:282
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop)
Definition: ipc_client.c:423
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
Definition: ipc_client.c:800
int pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
Ask a Pacemaker daemon to purge a node from its peer cache.
Definition: ipc_client.c:747
void pcmk_register_ipc_callback(pcmk_ipc_api_t *api, pcmk_ipc_callback_t cb, void *user_data)
Register a callback for IPC API events.
Definition: ipc_client.c:593
#define PCMK__SPECIAL_PID_AS_0(p)
Definition: ipc_internal.h:53
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:176
int pcmk__ipc_prepare_iov(uint32_t request, xmlNode *message, uint32_t max_send_size, struct iovec **result, ssize_t *bytes)
Definition: ipc_server.c:586
#define PCMK__SPECIAL_PID
Definition: ipc_internal.h:41
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
Definition: ipc_internal.h:183
#define crm_info(fmt, args...)
Definition: logging.h:361
#define crm_warn(fmt, args...)
Definition: logging.h:359
#define CRM_XS
Definition: logging.h:55
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:210
#define crm_notice(fmt, args...)
Definition: logging.h:360
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:309
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
Definition: logging.c:474
#define crm_debug(fmt, args...)
Definition: logging.h:363
#define crm_err(fmt, args...)
Definition: logging.h:358
#define crm_log_xml_trace(xml, text)
Definition: logging.h:372
#define crm_trace(fmt, args...)
Definition: logging.h:364
#define crm_log_xml_notice(xml, text)
Definition: logging.h:369
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:33
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:961
#define XML_ATTR_UNAME
Definition: msg_xml.h:157
#define T_ATTRD
Definition: msg_xml.h:85
#define F_ORIG
Definition: msg_xml.h:57
#define F_TYPE
Definition: msg_xml.h:69
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:431
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
unsigned int timeout
Definition: pcmk_fence.c:31
#define ENODATA
Definition: portability.h:145
char * strerror(int errnum)
const char * bz2_strerror(int rc)
Definition: results.c:742
const char * pcmk_strerror(int rc)
Definition: results.c:58
#define pcmk_err_generic
Definition: results.h:71
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:370
@ CRM_EX_DISCONNECT
Lost connection to something.
Definition: results.h:270
@ pcmk_rc_ok
Definition: results.h:146
@ pcmk_rc_ipc_unauthorized
Definition: results.h:124
@ pcmk_rc_error
Definition: results.h:142
@ pcmk_rc_ipc_unresponsive
Definition: results.h:123
#define pcmk_ok
Definition: results.h:68
int pcmk_rc2legacy(int rc)
Definition: results.c:415
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:428
enum crm_exit_e crm_exit_t
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:84
struct qb_ipc_response_header qb
void(* free_data)(void *api_data)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
void(* post_disconnect)(pcmk_ipc_api_t *api)
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
int(* post_connect)(pcmk_ipc_api_t *api)
enum pcmk_ipc_dispatch dispatch_type
mainloop_io_t * mainloop_io
pcmk__ipc_methods_t * cmds
pcmk_ipc_callback_t cb
enum pcmk_ipc_server server
void crm_xml_set_id(xmlNode *xml, const char *format,...) G_GNUC_PRINTF(2
xmlNode * string2xml(const char *input)
Definition: xml.c:869
void free_xml(xmlNode *child)
Definition: xml.c:824
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:696