pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
ipc_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2024 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(HAVE_UCRED) || defined(HAVE_SOCKPEERCRED)
13# ifdef HAVE_UCRED
14# ifndef _GNU_SOURCE
15# define _GNU_SOURCE
16# endif
17# endif
18# include <sys/socket.h>
19#elif defined(HAVE_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/common/xml.h>
30#include <crm/common/ipc.h>
32#include "crmcommon_private.h"
33
34static int is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
35 uid_t refuid, gid_t refgid, pid_t *gotpid,
36 uid_t *gotuid, gid_t *gotgid);
37
50int
52{
53 if (api == NULL) {
54 return EINVAL;
55 }
56
57 *api = calloc(1, sizeof(pcmk_ipc_api_t));
58 if (*api == NULL) {
59 return errno;
60 }
61
62 (*api)->server = server;
63 if (pcmk_ipc_name(*api, false) == NULL) {
65 *api = NULL;
66 return EOPNOTSUPP;
67 }
68
69 (*api)->ipc_size_max = 0;
70
71 // Set server methods and max_size (if not default)
72 switch (server) {
73 case pcmk_ipc_attrd:
74 (*api)->cmds = pcmk__attrd_api_methods();
75 break;
76
77 case pcmk_ipc_based:
78 (*api)->ipc_size_max = 512 * 1024; // 512KB
79 break;
80
82 (*api)->cmds = pcmk__controld_api_methods();
83 break;
84
85 case pcmk_ipc_execd:
86 break;
87
88 case pcmk_ipc_fenced:
89 break;
90
92 (*api)->cmds = pcmk__pacemakerd_api_methods();
93 break;
94
96 (*api)->cmds = pcmk__schedulerd_api_methods();
97 // @TODO max_size could vary by client, maybe take as argument?
98 (*api)->ipc_size_max = 5 * 1024 * 1024; // 5MB
99 break;
100 }
101 if ((*api)->cmds == NULL) {
102 pcmk_free_ipc_api(*api);
103 *api = NULL;
104 return ENOMEM;
105 }
106
107 (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false),
108 (*api)->ipc_size_max);
109 if ((*api)->ipc == NULL) {
110 pcmk_free_ipc_api(*api);
111 *api = NULL;
112 return ENOMEM;
113 }
114
115 // If daemon API has its own data to track, allocate it
116 if ((*api)->cmds->new_data != NULL) {
117 if ((*api)->cmds->new_data(*api) != pcmk_rc_ok) {
118 pcmk_free_ipc_api(*api);
119 *api = NULL;
120 return ENOMEM;
121 }
122 }
123 crm_trace("Created %s API IPC object", pcmk_ipc_name(*api, true));
124 return pcmk_rc_ok;
125}
126
127static void
128free_daemon_specific_data(pcmk_ipc_api_t *api)
129{
130 if ((api != NULL) && (api->cmds != NULL)) {
131 if ((api->cmds->free_data != NULL) && (api->api_data != NULL)) {
132 api->cmds->free_data(api->api_data);
133 api->api_data = NULL;
134 }
135 free(api->cmds);
136 api->cmds = NULL;
137 }
138}
139
149void
151 crm_exit_t status, void *event_data)
152{
153 if ((api != NULL) && (api->cb != NULL)) {
154 api->cb(api, event_type, status, event_data, api->user_data);
155 }
156}
157
166static void
167ipc_post_disconnect(gpointer user_data)
168{
169 pcmk_ipc_api_t *api = user_data;
170
171 crm_info("Disconnected from %s", pcmk_ipc_name(api, true));
172
173 // Perform any daemon-specific handling needed
174 if ((api->cmds != NULL) && (api->cmds->post_disconnect != NULL)) {
175 api->cmds->post_disconnect(api);
176 }
177
178 // Call client's registered event callback
180 NULL);
181
182 /* If this is being called from a running main loop, mainloop_gio_destroy()
183 * will free ipc and mainloop_io immediately after calling this function.
184 * If this is called from a stopped main loop, these will leak, so the best
185 * practice is to close the connection before stopping the main loop.
186 */
187 api->ipc = NULL;
188 api->mainloop_io = NULL;
189
190 if (api->free_on_disconnect) {
191 /* pcmk_free_ipc_api() has already been called, but did not free api
192 * or api->cmds because this function needed them. Do that now.
193 */
194 free_daemon_specific_data(api);
195 crm_trace("Freeing IPC API object after disconnect");
196 free(api);
197 }
198}
199
205void
207{
208 bool free_on_disconnect = false;
209
210 if (api == NULL) {
211 return;
212 }
213 crm_debug("Releasing %s IPC API", pcmk_ipc_name(api, true));
214
215 if (api->ipc != NULL) {
216 if (api->mainloop_io != NULL) {
217 /* We need to keep the api pointer itself around, because it is the
218 * user data for the IPC client destroy callback. That will be
219 * triggered by the pcmk_disconnect_ipc() call below, but it might
220 * happen later in the main loop (if still running).
221 *
222 * This flag tells the destroy callback to free the object. It can't
223 * do that unconditionally, because the application might call this
224 * function after a disconnect that happened by other means.
225 */
226 free_on_disconnect = api->free_on_disconnect = true;
227 }
228 pcmk_disconnect_ipc(api); // Frees api if free_on_disconnect is true
229 }
230 if (!free_on_disconnect) {
231 free_daemon_specific_data(api);
232 crm_trace("Freeing IPC API object");
233 free(api);
234 }
235}
236
246const char *
247pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
248{
249 if (api == NULL) {
250 return for_log? "Pacemaker" : NULL;
251 }
252 switch (api->server) {
253 case pcmk_ipc_attrd:
254 return for_log? "attribute manager" : PCMK__VALUE_ATTRD;
255
256 case pcmk_ipc_based:
257 return for_log? "CIB manager" : NULL /* PCMK__SERVER_BASED_RW */;
258
260 return for_log? "controller" : CRM_SYSTEM_CRMD;
261
262 case pcmk_ipc_execd:
263 return for_log? "executor" : NULL /* CRM_SYSTEM_LRMD */;
264
265 case pcmk_ipc_fenced:
266 return for_log? "fencer" : NULL /* "stonith-ng" */;
267
269 return for_log? "launcher" : CRM_SYSTEM_MCP;
270
272 return for_log? "scheduler" : CRM_SYSTEM_PENGINE;
273
274 default:
275 return for_log? "Pacemaker" : NULL;
276 }
277}
278
286bool
288{
289 return (api != NULL) && crm_ipc_connected(api->ipc);
290}
291
303static bool
304call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
305{
306 crm_log_xml_trace(message, "ipc-received");
307 if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
308 return api->cmds->dispatch(api, message);
309 }
310
311 return false;
312}
313
329static int
330dispatch_ipc_data(const char *buffer, pcmk_ipc_api_t *api)
331{
332 bool more = false;
333 xmlNode *msg;
334
335 if (buffer == NULL) {
336 crm_warn("Empty message received from %s IPC",
337 pcmk_ipc_name(api, true));
338 return ENOMSG;
339 }
340
341 msg = pcmk__xml_parse(buffer);
342 if (msg == NULL) {
343 crm_warn("Malformed message received from %s IPC",
344 pcmk_ipc_name(api, true));
345 return EPROTO;
346 }
347
348 more = call_api_dispatch(api, msg);
349 free_xml(msg);
350
351 if (more) {
352 return EINPROGRESS;
353 } else {
354 return pcmk_rc_ok;
355 }
356}
357
370static int
371dispatch_ipc_source_data(const char *buffer, ssize_t length, gpointer user_data)
372{
373 pcmk_ipc_api_t *api = user_data;
374
375 CRM_CHECK(api != NULL, return 0);
376 dispatch_ipc_data(buffer, api);
377 return 0;
378}
379
398int
399pcmk_poll_ipc(const pcmk_ipc_api_t *api, int timeout_ms)
400{
401 int rc;
402 struct pollfd pollfd = { 0, };
403
404 if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
405 return EINVAL;
406 }
407
408 rc = pcmk__ipc_fd(api->ipc, &(pollfd.fd));
409 if (rc != pcmk_rc_ok) {
410 crm_debug("Could not obtain file descriptor for %s IPC: %s",
411 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
412 return rc;
413 }
414
415 pollfd.events = POLLIN;
416 rc = poll(&pollfd, 1, timeout_ms);
417 if (rc < 0) {
418 /* Some UNIX systems return negative and set EAGAIN for failure to
419 * allocate memory; standardize the return code in that case
420 */
421 return (errno == EAGAIN)? ENOMEM : errno;
422 } else if (rc == 0) {
423 return EAGAIN;
424 }
425 return pcmk_rc_ok;
426}
427
438void
440{
441 if (api == NULL) {
442 return;
443 }
444 while (crm_ipc_ready(api->ipc) > 0) {
445 if (crm_ipc_read(api->ipc) > 0) {
446 dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
447 }
448 }
449}
450
451// \return Standard Pacemaker return code
452static int
453connect_with_main_loop(pcmk_ipc_api_t *api)
454{
455 int rc;
456
457 struct ipc_client_callbacks callbacks = {
458 .dispatch = dispatch_ipc_source_data,
459 .destroy = ipc_post_disconnect,
460 };
461
462 rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
463 &callbacks, &(api->mainloop_io));
464 if (rc != pcmk_rc_ok) {
465 return rc;
466 }
467 crm_debug("Connected to %s IPC (attached to main loop)",
468 pcmk_ipc_name(api, true));
469 /* After this point, api->mainloop_io owns api->ipc, so api->ipc
470 * should not be explicitly freed.
471 */
472 return pcmk_rc_ok;
473}
474
475// \return Standard Pacemaker return code
476static int
477connect_without_main_loop(pcmk_ipc_api_t *api)
478{
479 int rc = pcmk__connect_generic_ipc(api->ipc);
480
481 if (rc != pcmk_rc_ok) {
482 crm_ipc_close(api->ipc);
483 } else {
484 crm_debug("Connected to %s IPC (without main loop)",
485 pcmk_ipc_name(api, true));
486 }
487 return rc;
488}
489
500int
502 int attempts)
503{
504 int rc = pcmk_rc_ok;
505
506 if ((api == NULL) || (attempts < 1)) {
507 return EINVAL;
508 }
509
510 if (api->ipc == NULL) {
511 api->ipc = crm_ipc_new(pcmk_ipc_name(api, false), api->ipc_size_max);
512 if (api->ipc == NULL) {
513 return ENOMEM;
514 }
515 }
516
517 if (crm_ipc_connected(api->ipc)) {
518 crm_trace("Already connected to %s", pcmk_ipc_name(api, true));
519 return pcmk_rc_ok;
520 }
521
522 api->dispatch_type = dispatch_type;
523
524 crm_debug("Attempting connection to %s (up to %d time%s)",
525 pcmk_ipc_name(api, true), attempts, pcmk__plural_s(attempts));
526 for (int remaining = attempts - 1; remaining >= 0; --remaining) {
527 switch (dispatch_type) {
529 rc = connect_with_main_loop(api);
530 break;
531
534 rc = connect_without_main_loop(api);
535 break;
536 }
537
538 if ((remaining == 0) || ((rc != EAGAIN) && (rc != EALREADY))) {
539 break; // Result is final
540 }
541
542 // Retry after soft error (interrupted by signal, etc.)
543 pcmk__sleep_ms((attempts - remaining) * 500);
544 crm_debug("Re-attempting connection to %s (%d attempt%s remaining)",
545 pcmk_ipc_name(api, true), remaining,
546 pcmk__plural_s(remaining));
547 }
548
549 if (rc != pcmk_rc_ok) {
550 return rc;
551 }
552
553 if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
554 rc = api->cmds->post_connect(api);
555 if (rc != pcmk_rc_ok) {
556 crm_ipc_close(api->ipc);
557 }
558 }
559 return rc;
560}
561
570int
572{
573 int rc = pcmk__connect_ipc(api, dispatch_type, 2);
574
575 if (rc != pcmk_rc_ok) {
576 crm_err("Connection to %s failed: %s",
577 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
578 }
579 return rc;
580}
581
593void
595{
596 if ((api == NULL) || (api->ipc == NULL)) {
597 return;
598 }
599 switch (api->dispatch_type) {
601 {
602 mainloop_io_t *mainloop_io = api->mainloop_io;
603
604 // Make sure no code with access to api can use these again
605 api->mainloop_io = NULL;
606 api->ipc = NULL;
607
608 mainloop_del_ipc_client(mainloop_io);
609 // After this point api might have already been freed
610 }
611 break;
612
615 {
616 crm_ipc_t *ipc = api->ipc;
617
618 // Make sure no code with access to api can use ipc again
619 api->ipc = NULL;
620
621 // This should always be the case already, but to be safe
622 api->free_on_disconnect = false;
623
624 crm_ipc_close(ipc);
625 crm_ipc_destroy(ipc);
626 ipc_post_disconnect(api);
627 }
628 break;
629 }
630}
631
644void
646 void *user_data)
647{
648 if (api == NULL) {
649 return;
650 }
651 api->cb = cb;
652 api->user_data = user_data;
653}
654
667int
668pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
669{
670 int rc;
671 xmlNode *reply = NULL;
673
674 if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
675 return EINVAL;
676 }
677 crm_log_xml_trace(request, "ipc-sent");
678
679 // Synchronous dispatch requires waiting for a reply
681 && (api->cmds != NULL)
682 && (api->cmds->reply_expected != NULL)
683 && (api->cmds->reply_expected(api, request))) {
685 }
686
687 // The 0 here means a default timeout of 5 seconds
688 rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
689
690 if (rc < 0) {
691 return pcmk_legacy2rc(rc);
692 } else if (rc == 0) {
693 return ENODATA;
694 }
695
696 // With synchronous dispatch, we dispatch any reply now
697 if (reply != NULL) {
698 bool more = call_api_dispatch(api, reply);
699
700 free_xml(reply);
701
702 while (more) {
703 rc = crm_ipc_read(api->ipc);
704
705 if (rc == -EAGAIN) {
706 continue;
707 } else if (rc == -ENOMSG || rc == pcmk_ok) {
708 return pcmk_rc_ok;
709 } else if (rc < 0) {
710 return -rc;
711 }
712
713 rc = dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
714
715 if (rc == pcmk_rc_ok) {
716 more = false;
717 } else if (rc == EINPROGRESS) {
718 more = true;
719 } else {
720 continue;
721 }
722 }
723 }
724 return pcmk_rc_ok;
725}
726
749static xmlNode *
750create_purge_node_request(const pcmk_ipc_api_t *api, const char *node_name,
751 uint32_t nodeid)
752{
753 xmlNode *request = NULL;
754 const char *client = crm_system_name? crm_system_name : "client";
755
756 switch (api->server) {
757 case pcmk_ipc_attrd:
758 request = pcmk__xe_create(NULL, __func__);
763 pcmk__xe_add_node(request, node_name, nodeid);
764 break;
765
767 case pcmk_ipc_fenced:
769 request = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL,
770 pcmk_ipc_name(api, false), client, NULL);
771 if (nodeid > 0) {
772 crm_xml_add_ll(request, PCMK_XA_ID, (long long) nodeid);
773 }
774 crm_xml_add(request, PCMK_XA_UNAME, node_name);
775 break;
776
777 case pcmk_ipc_based:
778 case pcmk_ipc_execd:
780 break;
781 }
782 return request;
783}
784
796int
797pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
798{
799 int rc = 0;
800 xmlNode *request = NULL;
801
802 if (api == NULL) {
803 return EINVAL;
804 }
805 if ((node_name == NULL) && (nodeid == 0)) {
806 return EINVAL;
807 }
808
809 request = create_purge_node_request(api, node_name, nodeid);
810 if (request == NULL) {
811 return EOPNOTSUPP;
812 }
813 rc = pcmk__send_ipc_request(api, request);
814 free_xml(request);
815
816 crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
817 pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
818 return rc;
819}
820
821/*
822 * Generic IPC API (to eventually be deprecated as public API and made internal)
823 */
824
825struct crm_ipc_s {
826 struct pollfd pfd;
827 unsigned int max_buf_size; // maximum bytes we can send or receive over IPC
828 unsigned int buf_size; // size of allocated buffer
829 int msg_size;
830 int need_reply;
831 char *buffer;
832 char *server_name; // server IPC name being connected to
833 qb_ipcc_connection_t *ipc;
834};
835
849crm_ipc_t *
850crm_ipc_new(const char *name, size_t max_size)
851{
852 crm_ipc_t *client = NULL;
853
854 client = calloc(1, sizeof(crm_ipc_t));
855 if (client == NULL) {
856 crm_err("Could not create IPC connection: %s", strerror(errno));
857 return NULL;
858 }
859
860 client->server_name = strdup(name);
861 if (client->server_name == NULL) {
862 crm_err("Could not create %s IPC connection: %s",
863 name, strerror(errno));
864 free(client);
865 return NULL;
866 }
867 client->buf_size = pcmk__ipc_buffer_size(max_size);
868 client->buffer = malloc(client->buf_size);
869 if (client->buffer == NULL) {
870 crm_err("Could not create %s IPC connection: %s",
871 name, strerror(errno));
872 free(client->server_name);
873 free(client);
874 return NULL;
875 }
876
877 /* Clients initiating connection pick the max buf size */
878 client->max_buf_size = client->buf_size;
879
880 client->pfd.fd = -1;
881 client->pfd.events = POLLIN;
882 client->pfd.revents = 0;
883
884 return client;
885}
886
895int
897{
898 uid_t cl_uid = 0;
899 gid_t cl_gid = 0;
900 pid_t found_pid = 0;
901 uid_t found_uid = 0;
902 gid_t found_gid = 0;
903 int rc = pcmk_rc_ok;
904
905 if (ipc == NULL) {
906 return EINVAL;
907 }
908
909 ipc->need_reply = FALSE;
910 ipc->ipc = qb_ipcc_connect(ipc->server_name, ipc->buf_size);
911 if (ipc->ipc == NULL) {
912 return errno;
913 }
914
915 rc = qb_ipcc_fd_get(ipc->ipc, &ipc->pfd.fd);
916 if (rc < 0) { // -errno
917 crm_ipc_close(ipc);
918 return -rc;
919 }
920
921 rc = pcmk_daemon_user(&cl_uid, &cl_gid);
922 rc = pcmk_legacy2rc(rc);
923 if (rc != pcmk_rc_ok) {
924 crm_ipc_close(ipc);
925 return rc;
926 }
927
928 rc = is_ipc_provider_expected(ipc->ipc, ipc->pfd.fd, cl_uid, cl_gid,
929 &found_pid, &found_uid, &found_gid);
930 if (rc != pcmk_rc_ok) {
931 if (rc == pcmk_rc_ipc_unauthorized) {
932 crm_info("%s IPC provider authentication failed: process %lld has "
933 "uid %lld (expected %lld) and gid %lld (expected %lld)",
934 ipc->server_name,
935 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
936 (long long) found_uid, (long long) cl_uid,
937 (long long) found_gid, (long long) cl_gid);
938 }
939 crm_ipc_close(ipc);
940 return rc;
941 }
942
943 ipc->max_buf_size = qb_ipcc_get_buffer_size(ipc->ipc);
944 if (ipc->max_buf_size > ipc->buf_size) {
945 free(ipc->buffer);
946 ipc->buffer = calloc(ipc->max_buf_size, sizeof(char));
947 if (ipc->buffer == NULL) {
948 rc = errno;
949 crm_ipc_close(ipc);
950 return rc;
951 }
952 ipc->buf_size = ipc->max_buf_size;
953 }
954
955 return pcmk_rc_ok;
956}
957
967bool
969{
970 int rc = pcmk__connect_generic_ipc(client);
971
972 if (rc == pcmk_rc_ok) {
973 return true;
974 }
975 if ((client != NULL) && (client->ipc == NULL)) {
976 errno = (rc > 0)? rc : ENOTCONN;
977 crm_debug("Could not establish %s IPC connection: %s (%d)",
978 client->server_name, pcmk_rc_str(errno), errno);
979 } else if (rc == pcmk_rc_ipc_unauthorized) {
980 crm_err("%s IPC provider authentication failed",
981 (client == NULL)? "Pacemaker" : client->server_name);
982 errno = ECONNABORTED;
983 } else {
984 crm_perror(LOG_ERR,
985 "Could not verify authenticity of %s IPC provider",
986 (client == NULL)? "Pacemaker" : client->server_name);
987 errno = ENOTCONN;
988 }
989 return false;
990}
991
992void
994{
995 if (client) {
996 if (client->ipc) {
997 qb_ipcc_connection_t *ipc = client->ipc;
998
999 client->ipc = NULL;
1000 qb_ipcc_disconnect(ipc);
1001 }
1002 }
1003}
1004
1005void
1007{
1008 if (client) {
1009 if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
1010 crm_notice("Destroying active %s IPC connection",
1011 client->server_name);
1012 /* The next line is basically unsafe
1013 *
1014 * If this connection was attached to mainloop and mainloop is active,
1015 * the 'disconnected' callback will end up back here and we'll end
1016 * up free'ing the memory twice - something that can still happen
1017 * even without this if we destroy a connection and it closes before
1018 * we call exit
1019 */
1020 /* crm_ipc_close(client); */
1021 } else {
1022 crm_trace("Destroying inactive %s IPC connection",
1023 client->server_name);
1024 }
1025 free(client->buffer);
1026 free(client->server_name);
1027 free(client);
1028 }
1029}
1030
1040int
1042{
1043 if ((ipc == NULL) || (fd == NULL)) {
1044 return EINVAL;
1045 }
1046 if ((ipc->ipc == NULL) || (ipc->pfd.fd < 0)) {
1047 return ENOTCONN;
1048 }
1049 *fd = ipc->pfd.fd;
1050 return pcmk_rc_ok;
1051}
1052
1053int
1055{
1056 int fd = -1;
1057
1058 if (pcmk__ipc_fd(client, &fd) != pcmk_rc_ok) {
1059 crm_err("Could not obtain file descriptor for %s IPC",
1060 ((client == NULL)? "unspecified" : client->server_name));
1061 errno = EINVAL;
1062 return -EINVAL;
1063 }
1064 return fd;
1065}
1066
1067bool
1069{
1070 bool rc = FALSE;
1071
1072 if (client == NULL) {
1073 crm_trace("No client");
1074 return FALSE;
1075
1076 } else if (client->ipc == NULL) {
1077 crm_trace("No connection");
1078 return FALSE;
1079
1080 } else if (client->pfd.fd < 0) {
1081 crm_trace("Bad descriptor");
1082 return FALSE;
1083 }
1084
1085 rc = qb_ipcc_is_connected(client->ipc);
1086 if (rc == FALSE) {
1087 client->pfd.fd = -EINVAL;
1088 }
1089 return rc;
1090}
1091
1099int
1101{
1102 int rc;
1103
1104 CRM_ASSERT(client != NULL);
1105
1106 if (!crm_ipc_connected(client)) {
1107 return -ENOTCONN;
1108 }
1109
1110 client->pfd.revents = 0;
1111 rc = poll(&(client->pfd), 1, 0);
1112 return (rc < 0)? -errno : rc;
1113}
1114
1115// \return Standard Pacemaker return code
1116static int
1117crm_ipc_decompress(crm_ipc_t * client)
1118{
1119 pcmk__ipc_header_t *header = (pcmk__ipc_header_t *)(void*)client->buffer;
1120
1121 if (header->size_compressed) {
1122 int rc = 0;
1123 unsigned int size_u = 1 + header->size_uncompressed;
1124 /* never let buf size fall below our max size required for ipc reads. */
1125 unsigned int new_buf_size = QB_MAX((sizeof(pcmk__ipc_header_t) + size_u), client->max_buf_size);
1126 char *uncompressed = pcmk__assert_alloc(1, new_buf_size);
1127
1128 crm_trace("Decompressing message data %u bytes into %u bytes",
1129 header->size_compressed, size_u);
1130
1131 rc = BZ2_bzBuffToBuffDecompress(uncompressed + sizeof(pcmk__ipc_header_t), &size_u,
1132 client->buffer + sizeof(pcmk__ipc_header_t), header->size_compressed, 1, 0);
1133 rc = pcmk__bzlib2rc(rc);
1134
1135 if (rc != pcmk_rc_ok) {
1136 crm_err("Decompression failed: %s " CRM_XS " rc=%d",
1137 pcmk_rc_str(rc), rc);
1138 free(uncompressed);
1139 return rc;
1140 }
1141
1142 /*
1143 * This assert no longer holds true. For an identical msg, some clients may
1144 * require compression, and others may not. If that same msg (event) is sent
1145 * to multiple clients, it could result in some clients receiving a compressed
1146 * msg even though compression was not explicitly required for them.
1147 *
1148 * CRM_ASSERT((header->size_uncompressed + sizeof(pcmk__ipc_header_t)) >= ipc_buffer_max);
1149 */
1150 CRM_ASSERT(size_u == header->size_uncompressed);
1151
1152 memcpy(uncompressed, client->buffer, sizeof(pcmk__ipc_header_t)); /* Preserve the header */
1153 header = (pcmk__ipc_header_t *)(void*)uncompressed;
1154
1155 free(client->buffer);
1156 client->buf_size = new_buf_size;
1157 client->buffer = uncompressed;
1158 }
1159
1160 CRM_ASSERT(client->buffer[sizeof(pcmk__ipc_header_t) + header->size_uncompressed - 1] == 0);
1161 return pcmk_rc_ok;
1162}
1163
1164long
1166{
1167 pcmk__ipc_header_t *header = NULL;
1168
1169 CRM_ASSERT(client != NULL);
1170 CRM_ASSERT(client->ipc != NULL);
1171 CRM_ASSERT(client->buffer != NULL);
1172
1173 client->buffer[0] = 0;
1174 client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1175 client->buf_size, 0);
1176 if (client->msg_size >= 0) {
1177 int rc = crm_ipc_decompress(client);
1178
1179 if (rc != pcmk_rc_ok) {
1180 return pcmk_rc2legacy(rc);
1181 }
1182
1183 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1184 if (!pcmk__valid_ipc_header(header)) {
1185 return -EBADMSG;
1186 }
1187
1188 crm_trace("Received %s IPC event %d size=%u rc=%d text='%.100s'",
1189 client->server_name, header->qb.id, header->qb.size,
1190 client->msg_size,
1191 client->buffer + sizeof(pcmk__ipc_header_t));
1192
1193 } else {
1194 crm_trace("No message received from %s IPC: %s",
1195 client->server_name, pcmk_strerror(client->msg_size));
1196
1197 if (client->msg_size == -EAGAIN) {
1198 return -EAGAIN;
1199 }
1200 }
1201
1202 if (!crm_ipc_connected(client) || client->msg_size == -ENOTCONN) {
1203 crm_err("Connection to %s IPC failed", client->server_name);
1204 }
1205
1206 if (header) {
1207 /* Data excluding the header */
1208 return header->size_uncompressed;
1209 }
1210 return -ENOMSG;
1211}
1212
1213const char *
1215{
1216 CRM_ASSERT(client != NULL);
1217 return client->buffer + sizeof(pcmk__ipc_header_t);
1218}
1219
1220uint32_t
1222{
1223 pcmk__ipc_header_t *header = NULL;
1224
1225 CRM_ASSERT(client != NULL);
1226 if (client->buffer == NULL) {
1227 return 0;
1228 }
1229
1230 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1231 return header->flags;
1232}
1233
1234const char *
1236{
1237 CRM_ASSERT(client != NULL);
1238 return client->server_name;
1239}
1240
1241// \return Standard Pacemaker return code
1242static int
1243internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
1244 ssize_t *bytes)
1245{
1246 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1247 int rc = pcmk_rc_ok;
1248
1249 /* get the reply */
1250 crm_trace("Waiting on reply to %s IPC message %d",
1251 client->server_name, request_id);
1252 do {
1253
1254 *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1255 if (*bytes > 0) {
1256 pcmk__ipc_header_t *hdr = NULL;
1257
1258 rc = crm_ipc_decompress(client);
1259 if (rc != pcmk_rc_ok) {
1260 return rc;
1261 }
1262
1263 hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1264 if (hdr->qb.id == request_id) {
1265 /* Got it */
1266 break;
1267 } else if (hdr->qb.id < request_id) {
1268 xmlNode *bad = pcmk__xml_parse(crm_ipc_buffer(client));
1269
1270 crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1271 crm_log_xml_notice(bad, "OldIpcReply");
1272
1273 } else {
1274 xmlNode *bad = pcmk__xml_parse(crm_ipc_buffer(client));
1275
1276 crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1277 crm_log_xml_notice(bad, "ImpossibleReply");
1278 CRM_ASSERT(hdr->qb.id <= request_id);
1279 }
1280 } else if (!crm_ipc_connected(client)) {
1281 crm_err("%s IPC provider disconnected while waiting for message %d",
1282 client->server_name, request_id);
1283 break;
1284 }
1285
1286 } while (time(NULL) < timeout);
1287
1288 if (*bytes < 0) {
1289 rc = (int) -*bytes; // System errno
1290 }
1291 return rc;
1292}
1293
1307int
1308crm_ipc_send(crm_ipc_t *client, const xmlNode *message,
1309 enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
1310{
1311 int rc = 0;
1312 ssize_t qb_rc = 0;
1313 ssize_t bytes = 0;
1314 struct iovec *iov;
1315 static uint32_t id = 0;
1316 static int factor = 8;
1317 pcmk__ipc_header_t *header;
1318
1319 if (client == NULL) {
1320 crm_notice("Can't send IPC request without connection (bug?): %.100s",
1321 message);
1322 return -ENOTCONN;
1323
1324 } else if (!crm_ipc_connected(client)) {
1325 /* Don't even bother */
1326 crm_notice("Can't send %s IPC requests: Connection closed",
1327 client->server_name);
1328 return -ENOTCONN;
1329 }
1330
1331 if (ms_timeout == 0) {
1332 ms_timeout = 5000;
1333 }
1334
1335 if (client->need_reply) {
1336 qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1337 if (qb_rc < 0) {
1338 crm_warn("Sending %s IPC disabled until pending reply received",
1339 client->server_name);
1340 return -EALREADY;
1341
1342 } else {
1343 crm_notice("Sending %s IPC re-enabled after pending reply received",
1344 client->server_name);
1345 client->need_reply = FALSE;
1346 }
1347 }
1348
1349 id++;
1350 CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1351 rc = pcmk__ipc_prepare_iov(id, message, client->max_buf_size, &iov, &bytes);
1352 if (rc != pcmk_rc_ok) {
1353 crm_warn("Couldn't prepare %s IPC request: %s " CRM_XS " rc=%d",
1354 client->server_name, pcmk_rc_str(rc), rc);
1355 return pcmk_rc2legacy(rc);
1356 }
1357
1358 header = iov[0].iov_base;
1359 pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1360
1362 /* Don't look for a synchronous response */
1364 }
1365
1366 if(header->size_compressed) {
1367 if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
1368 crm_notice("Compressed message exceeds %d0%% of configured IPC "
1369 "limit (%u bytes); consider setting PCMK_ipc_buffer to "
1370 "%u or higher",
1371 factor, client->max_buf_size, 2 * client->max_buf_size);
1372 factor++;
1373 }
1374 }
1375
1376 crm_trace("Sending %s IPC request %d of %u bytes using %dms timeout",
1377 client->server_name, header->qb.id, header->qb.size, ms_timeout);
1378
1379 if ((ms_timeout > 0) || !pcmk_is_set(flags, crm_ipc_client_response)) {
1380
1381 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1382
1383 do {
1384 /* @TODO Is this check really needed? Won't qb_ipcc_sendv() return
1385 * an error if it's not connected?
1386 */
1387 if (!crm_ipc_connected(client)) {
1388 goto send_cleanup;
1389 }
1390
1391 qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1392 } while ((qb_rc == -EAGAIN) && (time(NULL) < timeout));
1393
1394 rc = (int) qb_rc; // Negative of system errno, or bytes sent
1395 if (qb_rc <= 0) {
1396 goto send_cleanup;
1397
1399 crm_trace("Not waiting for reply to %s IPC request %d",
1400 client->server_name, header->qb.id);
1401 goto send_cleanup;
1402 }
1403
1404 rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes);
1405 if (rc != pcmk_rc_ok) {
1406 /* We didn't get the reply in time, so disable future sends for now.
1407 * The only alternative would be to close the connection since we
1408 * don't know how to detect and discard out-of-sequence replies.
1409 *
1410 * @TODO Implement out-of-sequence detection
1411 */
1412 client->need_reply = TRUE;
1413 }
1414 rc = (int) bytes; // Negative system errno, or size of reply received
1415
1416 } else {
1417 // No timeout, and client response needed
1418 do {
1419 qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
1420 client->buf_size, -1);
1421 } while ((qb_rc == -EAGAIN) && crm_ipc_connected(client));
1422 rc = (int) qb_rc; // Negative system errno, or size of reply received
1423 }
1424
1425 if (rc > 0) {
1426 pcmk__ipc_header_t *hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1427
1428 crm_trace("Received %d-byte reply %d to %s IPC %d: %.100s",
1429 rc, hdr->qb.id, client->server_name, header->qb.id,
1430 crm_ipc_buffer(client));
1431
1432 if (reply) {
1433 *reply = pcmk__xml_parse(crm_ipc_buffer(client));
1434 }
1435
1436 } else {
1437 crm_trace("No reply to %s IPC %d: rc=%d",
1438 client->server_name, header->qb.id, rc);
1439 }
1440
1441 send_cleanup:
1442 if (!crm_ipc_connected(client)) {
1443 crm_notice("Couldn't send %s IPC request %d: Connection closed "
1444 CRM_XS " rc=%d", client->server_name, header->qb.id, rc);
1445
1446 } else if (rc == -ETIMEDOUT) {
1447 crm_warn("%s IPC request %d failed: %s after %dms " CRM_XS " rc=%d",
1448 client->server_name, header->qb.id, pcmk_strerror(rc),
1449 ms_timeout, rc);
1450 crm_write_blackbox(0, NULL);
1451
1452 } else if (rc <= 0) {
1453 crm_warn("%s IPC request %d failed: %s " CRM_XS " rc=%d",
1454 client->server_name, header->qb.id,
1455 ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1456 }
1457
1459 return rc;
1460}
1461
1479static int
1480is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
1481 uid_t refuid, gid_t refgid,
1482 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1483{
1484 int rc = EOPNOTSUPP;
1485 pid_t found_pid = 0;
1486 uid_t found_uid = 0;
1487 gid_t found_gid = 0;
1488
1489#ifdef HAVE_QB_IPCC_AUTH_GET
1490 if (qb_ipc != NULL) {
1491 rc = qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid);
1492 rc = -rc; // libqb returns 0 or -errno
1493 if (rc == pcmk_rc_ok) {
1494 goto found;
1495 }
1496 }
1497#endif
1498
1499#ifdef HAVE_UCRED
1500 {
1501 struct ucred ucred;
1502 socklen_t ucred_len = sizeof(ucred);
1503
1504 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) < 0) {
1505 rc = errno;
1506 } else if (ucred_len != sizeof(ucred)) {
1507 rc = EOPNOTSUPP;
1508 } else {
1509 found_pid = ucred.pid;
1510 found_uid = ucred.uid;
1511 found_gid = ucred.gid;
1512 goto found;
1513 }
1514 }
1515#endif
1516
1517#ifdef HAVE_SOCKPEERCRED
1518 {
1519 struct sockpeercred sockpeercred;
1520 socklen_t sockpeercred_len = sizeof(sockpeercred);
1521
1522 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1523 &sockpeercred, &sockpeercred_len) < 0) {
1524 rc = errno;
1525 } else if (sockpeercred_len != sizeof(sockpeercred)) {
1526 rc = EOPNOTSUPP;
1527 } else {
1528 found_pid = sockpeercred.pid;
1529 found_uid = sockpeercred.uid;
1530 found_gid = sockpeercred.gid;
1531 goto found;
1532 }
1533 }
1534#endif
1535
1536#ifdef HAVE_GETPEEREID // For example, FreeBSD
1537 if (getpeereid(sock, &found_uid, &found_gid) < 0) {
1538 rc = errno;
1539 } else {
1540 found_pid = PCMK__SPECIAL_PID;
1541 goto found;
1542 }
1543#endif
1544
1545#ifdef HAVE_GETPEERUCRED
1546 {
1547 ucred_t *ucred = NULL;
1548
1549 if (getpeerucred(sock, &ucred) < 0) {
1550 rc = errno;
1551 } else {
1552 found_pid = ucred_getpid(ucred);
1553 found_uid = ucred_geteuid(ucred);
1554 found_gid = ucred_getegid(ucred);
1555 ucred_free(ucred);
1556 goto found;
1557 }
1558 }
1559#endif
1560
1561 return rc; // If we get here, nothing succeeded
1562
1563found:
1564 if (gotpid != NULL) {
1565 *gotpid = found_pid;
1566 }
1567 if (gotuid != NULL) {
1568 *gotuid = found_uid;
1569 }
1570 if (gotgid != NULL) {
1571 *gotgid = found_gid;
1572 }
1573 if ((found_uid != 0) && (found_uid != refuid) && (found_gid != refgid)) {
1575 }
1576 return pcmk_rc_ok;
1577}
1578
1579int
1580crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
1581 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1582{
1583 int ret = is_ipc_provider_expected(NULL, sock, refuid, refgid,
1584 gotpid, gotuid, gotgid);
1585
1586 /* The old function had some very odd return codes*/
1587 if (ret == 0) {
1588 return 1;
1589 } else if (ret == pcmk_rc_ipc_unauthorized) {
1590 return 0;
1591 } else {
1592 return pcmk_rc2legacy(ret);
1593 }
1594}
1595
1596int
1598 gid_t refgid, pid_t *gotpid)
1599{
1600 static char last_asked_name[PATH_MAX / 2] = ""; /* log spam prevention */
1601 int fd;
1602 int rc = pcmk_rc_ipc_unresponsive;
1603 int auth_rc = 0;
1604 int32_t qb_rc;
1605 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1606 qb_ipcc_connection_t *c;
1607#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1608 struct pollfd pollfd = { 0, };
1609 int poll_rc;
1610
1611 c = qb_ipcc_connect_async(name, 0,
1612 &(pollfd.fd));
1613#else
1614 c = qb_ipcc_connect(name, 0);
1615#endif
1616 if (c == NULL) {
1617 crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1619 goto bail;
1620 }
1621#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1622 pollfd.events = POLLIN;
1623 do {
1624 poll_rc = poll(&pollfd, 1, 2000);
1625 } while ((poll_rc == -1) && (errno == EINTR));
1626
1627 /* If poll() failed, given that disconnect function is not registered yet,
1628 * qb_ipcc_disconnect() won't clean up the socket. In any case, call
1629 * qb_ipcc_connect_continue() here so that it may fail and do the cleanup
1630 * for us.
1631 */
1632 if (qb_ipcc_connect_continue(c) != 0) {
1633 crm_info("Could not connect to %s IPC: %s", name,
1634 (poll_rc == 0)?"timeout":strerror(errno));
1636 c = NULL; // qb_ipcc_connect_continue cleaned up for us
1637 goto bail;
1638 }
1639#endif
1640
1641 qb_rc = qb_ipcc_fd_get(c, &fd);
1642 if (qb_rc != 0) {
1643 rc = (int) -qb_rc; // System errno
1644 crm_err("Could not get fd from %s IPC: %s " CRM_XS " rc=%d",
1645 name, pcmk_rc_str(rc), rc);
1646 goto bail;
1647 }
1648
1649 auth_rc = is_ipc_provider_expected(c, fd, refuid, refgid,
1650 &found_pid, &found_uid, &found_gid);
1651 if (auth_rc == pcmk_rc_ipc_unauthorized) {
1652 crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1653 " process %lld (uid: %lld, gid: %lld)",
1654 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1655 (long long) found_uid, (long long) found_gid);
1657 goto bail;
1658 }
1659
1660 if (auth_rc != pcmk_rc_ok) {
1661 rc = auth_rc;
1662 crm_err("Could not get peer credentials from %s IPC: %s "
1663 CRM_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1664 goto bail;
1665 }
1666
1667 if (gotpid != NULL) {
1668 *gotpid = found_pid;
1669 }
1670
1671 rc = pcmk_rc_ok;
1672 if ((found_uid != refuid || found_gid != refgid)
1673 && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1674 if ((found_uid == 0) && (refuid != 0)) {
1675 crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1676 " credentials are %lld:%lld, hazard of violating"
1677 " the least privilege principle",
1678 name, (long long) refuid, (long long) refgid);
1679 } else {
1680 crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1681 " expected credentials are %lld:%lld, which may"
1682 " mean a different set of privileges than expected",
1683 name, (long long) found_uid, (long long) found_gid,
1684 (long long) refuid, (long long) refgid);
1685 }
1686 memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1687 }
1688
1689bail:
1690 if (c != NULL) {
1691 qb_ipcc_disconnect(c);
1692 }
1693 return rc;
1694}
const char * name
Definition cib.c:26
void pcmk__xe_add_node(xmlNode *xml, const char *node, int nodeid)
Definition nodes.c:127
int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, const struct ipc_client_callbacks *callbacks, mainloop_io_t **source)
Connect to IPC and add it as a main loop source.
Definition mainloop.c:863
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition nvpair.c:903
void pcmk__sleep_ms(unsigned int ms)
Definition utils.c:471
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:297
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:125
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:98
A dumping ground.
#define CRM_SYSTEM_CRMD
Definition crm.h:90
#define CRM_SYSTEM_MCP
Definition crm.h:95
#define CRM_OP_RM_NODE_CACHE
Definition crm.h:139
char * crm_system_name
Definition utils.c:50
#define CRM_SYSTEM_PENGINE
Definition crm.h:92
#define PCMK__ATTRD_CMD_PEER_REMOVE
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__attrd_api_methods(void)
Definition ipc_attrd.c:118
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)
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:126
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition ipc.h:49
crm_ipc_flags
Definition ipc.h:164
@ crm_ipc_flags_none
Definition ipc.h:165
@ crm_ipc_client_response
Definition ipc.h:170
@ crm_ipc_proxied
Definition ipc.h:169
void pcmk_free_ipc_event(struct iovec *event)
Free an I/O vector created by pcmk__ipc_prepare_iov()
Definition ipc_server.c:259
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
Definition ipc.h:89
@ pcmk_ipc_event_disconnect
Termination of IPC connection.
Definition ipc.h:93
pcmk_ipc_server
Available IPC interfaces.
Definition ipc.h:77
@ pcmk_ipc_schedulerd
Scheduler.
Definition ipc.h:84
@ pcmk_ipc_based
CIB manager.
Definition ipc.h:79
@ pcmk_ipc_execd
Executor.
Definition ipc.h:81
@ pcmk_ipc_pacemakerd
Launcher.
Definition ipc.h:83
@ pcmk_ipc_attrd
Attribute manager.
Definition ipc.h:78
@ pcmk_ipc_controld
Controller.
Definition ipc.h:80
@ pcmk_ipc_fenced
Fencer.
Definition ipc.h:82
pcmk_ipc_dispatch
How IPC replies should be dispatched.
Definition ipc.h:102
@ pcmk_ipc_dispatch_sync
Sending a command will wait for any reply.
Definition ipc.h:105
@ pcmk_ipc_dispatch_poll
Caller will poll and dispatch IPC.
Definition ipc.h:104
@ pcmk_ipc_dispatch_main
Attach IPC to GMainLoop for dispatch.
Definition ipc.h:103
struct crm_ipc_s crm_ipc_t
Definition ipc.h:184
int pcmk_poll_ipc(const pcmk_ipc_api_t *api, int timeout_ms)
Check whether an IPC connection has data available (without main loop)
Definition ipc_client.c:399
void crm_ipc_destroy(crm_ipc_t *client)
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
Definition ipc_client.c:896
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance.
Definition ipc_client.c:594
const char * crm_ipc_name(crm_ipc_t *client)
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
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:571
long crm_ipc_read(crm_ipc_t *client)
int crm_ipc_get_fd(crm_ipc_t *client)
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition ipc_client.c:668
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
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:150
int pcmk__connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type, int attempts)
Definition ipc_client.c:501
bool crm_ipc_connected(crm_ipc_t *client)
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition ipc_client.c:968
const char * pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection.
Definition ipc_client.c:247
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)
void crm_ipc_close(crm_ipc_t *client)
Definition ipc_client.c:993
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
Definition ipc_client.c:206
int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid)
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
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:51
const char * crm_ipc_buffer(crm_ipc_t *client)
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active.
Definition ipc_client.c:287
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop)
Definition ipc_client.c:439
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:850
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:797
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:645
#define PCMK__SPECIAL_PID_AS_0(p)
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
#define PCMK__SPECIAL_PID
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
int pcmk__ipc_prepare_iov(uint32_t request, const xmlNode *message, uint32_t max_send_size, struct iovec **result, ssize_t *bytes)
Definition ipc_server.c:575
#define crm_info(fmt, args...)
Definition logging.h:397
void crm_write_blackbox(int nsig, const struct qb_log_callsite *callsite)
Definition logging.c:505
#define crm_warn(fmt, args...)
Definition logging.h:392
#define CRM_XS
Definition logging.h:56
#define CRM_LOG_ASSERT(expr)
Definition logging.h:228
#define crm_notice(fmt, args...)
Definition logging.h:395
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:331
#define CRM_CHECK(expr, failure_action)
Definition logging.h:245
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_err(fmt, args...)
Definition logging.h:389
#define crm_log_xml_trace(xml, text)
Definition logging.h:410
#define crm_trace(fmt, args...)
Definition logging.h:402
#define crm_log_xml_notice(xml, text)
Definition logging.h:407
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:35
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:943
const char * crm_xml_add_ll(xmlNode *node, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
Definition nvpair.c:398
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:301
#define PCMK__VALUE_ATTRD
unsigned int timeout
Definition pcmk_fence.c:32
#define ENODATA
const char * pcmk_strerror(int rc)
Definition results.c:149
#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:501
@ CRM_EX_DISCONNECT
Lost connection to something.
Definition results.h:288
@ pcmk_rc_ok
Definition results.h:162
@ pcmk_rc_ipc_unauthorized
Definition results.h:139
@ pcmk_rc_ipc_unresponsive
Definition results.h:138
#define pcmk_ok
Definition results.h:69
int pcmk_rc2legacy(int rc)
Definition results.c:546
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:559
enum crm_exit_e crm_exit_t
int pcmk__bzlib2rc(int bz2)
Map a bz2 return code to the most similar Pacemaker return code.
Definition results.c:906
#define pcmk__plural_s(i)
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition mainloop.h:94
struct qb_ipc_response_header qb
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
void(* free_data)(void *api_data)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
void(* post_disconnect)(pcmk_ipc_api_t *api)
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
Wrappers for and extensions to libxml2.
void free_xml(xmlNode *child)
Definition xml.c:867
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
xmlNode * pcmk__xml_parse(const char *input)
Definition xml_io.c:244
#define PCMK_XA_TASK
Definition xml_names.h:419
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XA_UNAME
Definition xml_names.h:426
#define PCMK__XA_REAP
#define PCMK__XA_T
#define PCMK__XA_SRC