pacemaker 2.1.6-6fdc9deea29
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
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(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/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 (*api)->cmds = pcmk__attrd_api_methods();
71 break;
72
73 case pcmk_ipc_based:
74 (*api)->ipc_size_max = 512 * 1024; // 512KB
75 break;
76
78 (*api)->cmds = pcmk__controld_api_methods();
79 break;
80
81 case pcmk_ipc_execd:
82 break;
83
84 case pcmk_ipc_fenced:
85 break;
86
88 (*api)->cmds = pcmk__pacemakerd_api_methods();
89 break;
90
92 (*api)->cmds = pcmk__schedulerd_api_methods();
93 // @TODO max_size could vary by client, maybe take as argument?
94 (*api)->ipc_size_max = 5 * 1024 * 1024; // 5MB
95 break;
96 }
97 if ((*api)->cmds == NULL) {
99 *api = NULL;
100 return ENOMEM;
101 }
102
103 (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false),
104 (*api)->ipc_size_max);
105 if ((*api)->ipc == NULL) {
106 pcmk_free_ipc_api(*api);
107 *api = NULL;
108 return ENOMEM;
109 }
110
111 // If daemon API has its own data to track, allocate it
112 if ((*api)->cmds->new_data != NULL) {
113 if ((*api)->cmds->new_data(*api) != pcmk_rc_ok) {
114 pcmk_free_ipc_api(*api);
115 *api = NULL;
116 return ENOMEM;
117 }
118 }
119 crm_trace("Created %s API IPC object", pcmk_ipc_name(*api, true));
120 return pcmk_rc_ok;
121}
122
123static void
124free_daemon_specific_data(pcmk_ipc_api_t *api)
125{
126 if ((api != NULL) && (api->cmds != NULL)) {
127 if ((api->cmds->free_data != NULL) && (api->api_data != NULL)) {
128 api->cmds->free_data(api->api_data);
129 api->api_data = NULL;
130 }
131 free(api->cmds);
132 api->cmds = NULL;
133 }
134}
135
145void
147 crm_exit_t status, void *event_data)
148{
149 if ((api != NULL) && (api->cb != NULL)) {
150 api->cb(api, event_type, status, event_data, api->user_data);
151 }
152}
153
162static void
163ipc_post_disconnect(gpointer user_data)
164{
165 pcmk_ipc_api_t *api = user_data;
166
167 crm_info("Disconnected from %s IPC API", pcmk_ipc_name(api, true));
168
169 // Perform any daemon-specific handling needed
170 if ((api->cmds != NULL) && (api->cmds->post_disconnect != NULL)) {
171 api->cmds->post_disconnect(api);
172 }
173
174 // Call client's registered event callback
176 NULL);
177
178 /* If this is being called from a running main loop, mainloop_gio_destroy()
179 * will free ipc and mainloop_io immediately after calling this function.
180 * If this is called from a stopped main loop, these will leak, so the best
181 * practice is to close the connection before stopping the main loop.
182 */
183 api->ipc = NULL;
184 api->mainloop_io = NULL;
185
186 if (api->free_on_disconnect) {
187 /* pcmk_free_ipc_api() has already been called, but did not free api
188 * or api->cmds because this function needed them. Do that now.
189 */
190 free_daemon_specific_data(api);
191 crm_trace("Freeing IPC API object after disconnect");
192 free(api);
193 }
194}
195
201void
203{
204 bool free_on_disconnect = false;
205
206 if (api == NULL) {
207 return;
208 }
209 crm_debug("Releasing %s IPC API", pcmk_ipc_name(api, true));
210
211 if (api->ipc != NULL) {
212 if (api->mainloop_io != NULL) {
213 /* We need to keep the api pointer itself around, because it is the
214 * user data for the IPC client destroy callback. That will be
215 * triggered by the pcmk_disconnect_ipc() call below, but it might
216 * happen later in the main loop (if still running).
217 *
218 * This flag tells the destroy callback to free the object. It can't
219 * do that unconditionally, because the application might call this
220 * function after a disconnect that happened by other means.
221 */
222 free_on_disconnect = api->free_on_disconnect = true;
223 }
224 pcmk_disconnect_ipc(api); // Frees api if free_on_disconnect is true
225 }
226 if (!free_on_disconnect) {
227 free_daemon_specific_data(api);
228 crm_trace("Freeing IPC API object");
229 free(api);
230 }
231}
232
242const char *
243pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
244{
245 if (api == NULL) {
246 return for_log? "Pacemaker" : NULL;
247 }
248 switch (api->server) {
249 case pcmk_ipc_attrd:
250 return for_log? "attribute manager" : T_ATTRD;
251
252 case pcmk_ipc_based:
253 return for_log? "CIB manager" : NULL /* PCMK__SERVER_BASED_RW */;
254
256 return for_log? "controller" : CRM_SYSTEM_CRMD;
257
258 case pcmk_ipc_execd:
259 return for_log? "executor" : NULL /* CRM_SYSTEM_LRMD */;
260
261 case pcmk_ipc_fenced:
262 return for_log? "fencer" : NULL /* "stonith-ng" */;
263
265 return for_log? "launcher" : CRM_SYSTEM_MCP;
266
268 return for_log? "scheduler" : CRM_SYSTEM_PENGINE;
269
270 default:
271 return for_log? "Pacemaker" : NULL;
272 }
273}
274
282bool
284{
285 return (api != NULL) && crm_ipc_connected(api->ipc);
286}
287
299static bool
300call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
301{
302 crm_log_xml_trace(message, "ipc-received");
303 if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
304 return api->cmds->dispatch(api, message);
305 }
306
307 return false;
308}
309
325static int
326dispatch_ipc_data(const char *buffer, pcmk_ipc_api_t *api)
327{
328 bool more = false;
329 xmlNode *msg;
330
331 if (buffer == NULL) {
332 crm_warn("Empty message received from %s IPC",
333 pcmk_ipc_name(api, true));
334 return ENOMSG;
335 }
336
337 msg = string2xml(buffer);
338 if (msg == NULL) {
339 crm_warn("Malformed message received from %s IPC",
340 pcmk_ipc_name(api, true));
341 return EPROTO;
342 }
343
344 more = call_api_dispatch(api, msg);
345 free_xml(msg);
346
347 if (more) {
348 return EINPROGRESS;
349 } else {
350 return pcmk_rc_ok;
351 }
352}
353
366static int
367dispatch_ipc_source_data(const char *buffer, ssize_t length, gpointer user_data)
368{
369 pcmk_ipc_api_t *api = user_data;
370
371 CRM_CHECK(api != NULL, return 0);
372 dispatch_ipc_data(buffer, api);
373 return 0;
374}
375
394int
395pcmk_poll_ipc(const pcmk_ipc_api_t *api, int timeout_ms)
396{
397 int rc;
398 struct pollfd pollfd = { 0, };
399
400 if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
401 return EINVAL;
402 }
403 pollfd.fd = crm_ipc_get_fd(api->ipc);
404 pollfd.events = POLLIN;
405 rc = poll(&pollfd, 1, timeout_ms);
406 if (rc < 0) {
407 /* Some UNIX systems return negative and set EAGAIN for failure to
408 * allocate memory; standardize the return code in that case
409 */
410 return (errno == EAGAIN)? ENOMEM : errno;
411 } else if (rc == 0) {
412 return EAGAIN;
413 }
414 return pcmk_rc_ok;
415}
416
427void
429{
430 if (api == NULL) {
431 return;
432 }
433 while (crm_ipc_ready(api->ipc) > 0) {
434 if (crm_ipc_read(api->ipc) > 0) {
435 dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
436 }
437 }
438}
439
440// \return Standard Pacemaker return code
441static int
442connect_with_main_loop(pcmk_ipc_api_t *api)
443{
444 int rc;
445
446 struct ipc_client_callbacks callbacks = {
447 .dispatch = dispatch_ipc_source_data,
448 .destroy = ipc_post_disconnect,
449 };
450
451 rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
452 &callbacks, &(api->mainloop_io));
453 if (rc != pcmk_rc_ok) {
454 return rc;
455 }
456 crm_debug("Connected to %s IPC (attached to main loop)",
457 pcmk_ipc_name(api, true));
458 /* After this point, api->mainloop_io owns api->ipc, so api->ipc
459 * should not be explicitly freed.
460 */
461 return pcmk_rc_ok;
462}
463
464// \return Standard Pacemaker return code
465static int
466connect_without_main_loop(pcmk_ipc_api_t *api)
467{
468 int rc;
469
470 if (!crm_ipc_connect(api->ipc)) {
471 rc = errno;
472 crm_ipc_close(api->ipc);
473 return rc;
474 }
475 crm_debug("Connected to %s IPC (without main loop)",
476 pcmk_ipc_name(api, true));
477 return pcmk_rc_ok;
478}
479
488int
490{
491 const int n_attempts = 2;
492 int rc = pcmk_rc_ok;
493
494 if (api == NULL) {
495 crm_err("Cannot connect to uninitialized API object");
496 return EINVAL;
497 }
498
499 if (api->ipc == NULL) {
500 api->ipc = crm_ipc_new(pcmk_ipc_name(api, false),
501 api->ipc_size_max);
502 if (api->ipc == NULL) {
503 crm_err("Failed to re-create IPC API");
504 return ENOMEM;
505 }
506 }
507
508 if (crm_ipc_connected(api->ipc)) {
509 crm_trace("Already connected to %s IPC API", pcmk_ipc_name(api, true));
510 return pcmk_rc_ok;
511 }
512
513 api->dispatch_type = dispatch_type;
514
515 for (int i = 0; i < n_attempts; i++) {
516 switch (dispatch_type) {
518 rc = connect_with_main_loop(api);
519 break;
520
523 rc = connect_without_main_loop(api);
524 break;
525 }
526
527 if (rc != EAGAIN) {
528 break;
529 }
530
531 /* EAGAIN may occur due to interruption by a signal or due to some
532 * transient issue. Try one more time to be more resilient.
533 */
534 if (i < (n_attempts - 1)) {
535 crm_trace("Connection to %s IPC API failed with EAGAIN, retrying",
536 pcmk_ipc_name(api, true));
537 }
538 }
539
540 if (rc != pcmk_rc_ok) {
541 return rc;
542 }
543
544 if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
545 rc = api->cmds->post_connect(api);
546 if (rc != pcmk_rc_ok) {
547 crm_ipc_close(api->ipc);
548 }
549 }
550 return rc;
551}
552
564void
566{
567 if ((api == NULL) || (api->ipc == NULL)) {
568 return;
569 }
570 switch (api->dispatch_type) {
572 {
573 mainloop_io_t *mainloop_io = api->mainloop_io;
574
575 // Make sure no code with access to api can use these again
576 api->mainloop_io = NULL;
577 api->ipc = NULL;
578
579 mainloop_del_ipc_client(mainloop_io);
580 // After this point api might have already been freed
581 }
582 break;
583
586 {
587 crm_ipc_t *ipc = api->ipc;
588
589 // Make sure no code with access to api can use ipc again
590 api->ipc = NULL;
591
592 // This should always be the case already, but to be safe
593 api->free_on_disconnect = false;
594
595 crm_ipc_close(ipc);
596 crm_ipc_destroy(ipc);
597 ipc_post_disconnect(api);
598 }
599 break;
600 }
601}
602
615void
617 void *user_data)
618{
619 if (api == NULL) {
620 return;
621 }
622 api->cb = cb;
623 api->user_data = user_data;
624}
625
638int
640{
641 int rc;
642 xmlNode *reply = NULL;
644
645 if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
646 return EINVAL;
647 }
648 crm_log_xml_trace(request, "ipc-sent");
649
650 // Synchronous dispatch requires waiting for a reply
652 && (api->cmds != NULL)
653 && (api->cmds->reply_expected != NULL)
654 && (api->cmds->reply_expected(api, request))) {
656 }
657
658 // The 0 here means a default timeout of 5 seconds
659 rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
660
661 if (rc < 0) {
662 return pcmk_legacy2rc(rc);
663 } else if (rc == 0) {
664 return ENODATA;
665 }
666
667 // With synchronous dispatch, we dispatch any reply now
668 if (reply != NULL) {
669 bool more = call_api_dispatch(api, reply);
670
671 free_xml(reply);
672
673 while (more) {
674 rc = crm_ipc_read(api->ipc);
675
676 if (rc == -EAGAIN) {
677 continue;
678 } else if (rc == -ENOMSG || rc == pcmk_ok) {
679 return pcmk_rc_ok;
680 } else if (rc < 0) {
681 return -rc;
682 }
683
684 rc = dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
685
686 if (rc == pcmk_rc_ok) {
687 more = false;
688 } else if (rc == EINPROGRESS) {
689 more = true;
690 } else {
691 continue;
692 }
693 }
694 }
695 return pcmk_rc_ok;
696}
697
720static xmlNode *
721create_purge_node_request(const pcmk_ipc_api_t *api, const char *node_name,
722 uint32_t nodeid)
723{
724 xmlNode *request = NULL;
725 const char *client = crm_system_name? crm_system_name : "client";
726
727 switch (api->server) {
728 case pcmk_ipc_attrd:
729 request = create_xml_node(NULL, __func__);
730 crm_xml_add(request, F_TYPE, T_ATTRD);
733 pcmk__xe_add_node(request, node_name, nodeid);
734 break;
735
737 case pcmk_ipc_fenced:
739 request = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL,
740 pcmk_ipc_name(api, false), client, NULL);
741 if (nodeid > 0) {
742 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
743 }
744 crm_xml_add(request, XML_ATTR_UNAME, node_name);
745 break;
746
747 case pcmk_ipc_based:
748 case pcmk_ipc_execd:
750 break;
751 }
752 return request;
753}
754
766int
767pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
768{
769 int rc = 0;
770 xmlNode *request = NULL;
771
772 if (api == NULL) {
773 return EINVAL;
774 }
775 if ((node_name == NULL) && (nodeid == 0)) {
776 return EINVAL;
777 }
778
779 request = create_purge_node_request(api, node_name, nodeid);
780 if (request == NULL) {
781 return EOPNOTSUPP;
782 }
783 rc = pcmk__send_ipc_request(api, request);
784 free_xml(request);
785
786 crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
787 pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
788 return rc;
789}
790
791/*
792 * Generic IPC API (to eventually be deprecated as public API and made internal)
793 */
794
795struct crm_ipc_s {
796 struct pollfd pfd;
797 unsigned int max_buf_size; // maximum bytes we can send or receive over IPC
798 unsigned int buf_size; // size of allocated buffer
799 int msg_size;
800 int need_reply;
801 char *buffer;
802 char *server_name; // server IPC name being connected to
803 qb_ipcc_connection_t *ipc;
804};
805
819crm_ipc_t *
820crm_ipc_new(const char *name, size_t max_size)
821{
822 crm_ipc_t *client = NULL;
823
824 client = calloc(1, sizeof(crm_ipc_t));
825 if (client == NULL) {
826 crm_err("Could not create IPC connection: %s", strerror(errno));
827 return NULL;
828 }
829
830 client->server_name = strdup(name);
831 if (client->server_name == NULL) {
832 crm_err("Could not create %s IPC connection: %s",
833 name, strerror(errno));
834 free(client);
835 return NULL;
836 }
837 client->buf_size = pcmk__ipc_buffer_size(max_size);
838 client->buffer = malloc(client->buf_size);
839 if (client->buffer == NULL) {
840 crm_err("Could not create %s IPC connection: %s",
841 name, strerror(errno));
842 free(client->server_name);
843 free(client);
844 return NULL;
845 }
846
847 /* Clients initiating connection pick the max buf size */
848 client->max_buf_size = client->buf_size;
849
850 client->pfd.fd = -1;
851 client->pfd.events = POLLIN;
852 client->pfd.revents = 0;
853
854 return client;
855}
856
866bool
868{
869 uid_t cl_uid = 0;
870 gid_t cl_gid = 0;
871 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
872 int rv;
873
874 if (client == NULL) {
875 errno = EINVAL;
876 return false;
877 }
878
879 client->need_reply = FALSE;
880 client->ipc = qb_ipcc_connect(client->server_name, client->buf_size);
881
882 if (client->ipc == NULL) {
883 crm_debug("Could not establish %s IPC connection: %s (%d)",
884 client->server_name, pcmk_rc_str(errno), errno);
885 return false;
886 }
887
888 client->pfd.fd = crm_ipc_get_fd(client);
889 if (client->pfd.fd < 0) {
890 rv = errno;
891 /* message already omitted */
892 crm_ipc_close(client);
893 errno = rv;
894 return false;
895 }
896
897 rv = pcmk_daemon_user(&cl_uid, &cl_gid);
898 if (rv < 0) {
899 /* message already omitted */
900 crm_ipc_close(client);
901 errno = -rv;
902 return false;
903 }
904
905 if ((rv = pcmk__crm_ipc_is_authentic_process(client->ipc, client->pfd.fd, cl_uid, cl_gid,
906 &found_pid, &found_uid,
907 &found_gid)) == pcmk_rc_ipc_unauthorized) {
908 crm_err("%s IPC provider authentication failed: process %lld has "
909 "uid %lld (expected %lld) and gid %lld (expected %lld)",
910 client->server_name,
911 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
912 (long long) found_uid, (long long) cl_uid,
913 (long long) found_gid, (long long) cl_gid);
914 crm_ipc_close(client);
915 errno = ECONNABORTED;
916 return false;
917
918 } else if (rv != pcmk_rc_ok) {
919 crm_perror(LOG_ERR, "Could not verify authenticity of %s IPC provider",
920 client->server_name);
921 crm_ipc_close(client);
922 if (rv > 0) {
923 errno = rv;
924 } else {
925 errno = ENOTCONN;
926 }
927 return false;
928 }
929
930 qb_ipcc_context_set(client->ipc, client);
931
932 client->max_buf_size = qb_ipcc_get_buffer_size(client->ipc);
933 if (client->max_buf_size > client->buf_size) {
934 free(client->buffer);
935 client->buffer = calloc(1, client->max_buf_size);
936 client->buf_size = client->max_buf_size;
937 }
938 return true;
939}
940
941void
943{
944 if (client) {
945 if (client->ipc) {
946 qb_ipcc_connection_t *ipc = client->ipc;
947
948 client->ipc = NULL;
949 qb_ipcc_disconnect(ipc);
950 }
951 }
952}
953
954void
956{
957 if (client) {
958 if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
959 crm_notice("Destroying active %s IPC connection",
960 client->server_name);
961 /* The next line is basically unsafe
962 *
963 * If this connection was attached to mainloop and mainloop is active,
964 * the 'disconnected' callback will end up back here and we'll end
965 * up free'ing the memory twice - something that can still happen
966 * even without this if we destroy a connection and it closes before
967 * we call exit
968 */
969 /* crm_ipc_close(client); */
970 } else {
971 crm_trace("Destroying inactive %s IPC connection",
972 client->server_name);
973 }
974 free(client->buffer);
975 free(client->server_name);
976 free(client);
977 }
978}
979
980int
982{
983 int fd = 0;
984
985 if (client && client->ipc && (qb_ipcc_fd_get(client->ipc, &fd) == 0)) {
986 return fd;
987 }
988 errno = EINVAL;
989 crm_perror(LOG_ERR, "Could not obtain file descriptor for %s IPC",
990 (client? client->server_name : "unspecified"));
991 return -errno;
992}
993
994bool
996{
997 bool rc = FALSE;
998
999 if (client == NULL) {
1000 crm_trace("No client");
1001 return FALSE;
1002
1003 } else if (client->ipc == NULL) {
1004 crm_trace("No connection");
1005 return FALSE;
1006
1007 } else if (client->pfd.fd < 0) {
1008 crm_trace("Bad descriptor");
1009 return FALSE;
1010 }
1011
1012 rc = qb_ipcc_is_connected(client->ipc);
1013 if (rc == FALSE) {
1014 client->pfd.fd = -EINVAL;
1015 }
1016 return rc;
1017}
1018
1026int
1028{
1029 int rc;
1030
1031 CRM_ASSERT(client != NULL);
1032
1033 if (!crm_ipc_connected(client)) {
1034 return -ENOTCONN;
1035 }
1036
1037 client->pfd.revents = 0;
1038 rc = poll(&(client->pfd), 1, 0);
1039 return (rc < 0)? -errno : rc;
1040}
1041
1042// \return Standard Pacemaker return code
1043static int
1044crm_ipc_decompress(crm_ipc_t * client)
1045{
1046 pcmk__ipc_header_t *header = (pcmk__ipc_header_t *)(void*)client->buffer;
1047
1048 if (header->size_compressed) {
1049 int rc = 0;
1050 unsigned int size_u = 1 + header->size_uncompressed;
1051 /* never let buf size fall below our max size required for ipc reads. */
1052 unsigned int new_buf_size = QB_MAX((sizeof(pcmk__ipc_header_t) + size_u), client->max_buf_size);
1053 char *uncompressed = calloc(1, new_buf_size);
1054
1055 crm_trace("Decompressing message data %u bytes into %u bytes",
1056 header->size_compressed, size_u);
1057
1058 rc = BZ2_bzBuffToBuffDecompress(uncompressed + sizeof(pcmk__ipc_header_t), &size_u,
1059 client->buffer + sizeof(pcmk__ipc_header_t), header->size_compressed, 1, 0);
1060
1061 if (rc != BZ_OK) {
1062 crm_err("Decompression failed: %s " CRM_XS " bzerror=%d",
1063 bz2_strerror(rc), rc);
1064 free(uncompressed);
1065 return EILSEQ;
1066 }
1067
1068 /*
1069 * This assert no longer holds true. For an identical msg, some clients may
1070 * require compression, and others may not. If that same msg (event) is sent
1071 * to multiple clients, it could result in some clients receiving a compressed
1072 * msg even though compression was not explicitly required for them.
1073 *
1074 * CRM_ASSERT((header->size_uncompressed + sizeof(pcmk__ipc_header_t)) >= ipc_buffer_max);
1075 */
1076 CRM_ASSERT(size_u == header->size_uncompressed);
1077
1078 memcpy(uncompressed, client->buffer, sizeof(pcmk__ipc_header_t)); /* Preserve the header */
1079 header = (pcmk__ipc_header_t *)(void*)uncompressed;
1080
1081 free(client->buffer);
1082 client->buf_size = new_buf_size;
1083 client->buffer = uncompressed;
1084 }
1085
1086 CRM_ASSERT(client->buffer[sizeof(pcmk__ipc_header_t) + header->size_uncompressed - 1] == 0);
1087 return pcmk_rc_ok;
1088}
1089
1090long
1092{
1093 pcmk__ipc_header_t *header = NULL;
1094
1095 CRM_ASSERT(client != NULL);
1096 CRM_ASSERT(client->ipc != NULL);
1097 CRM_ASSERT(client->buffer != NULL);
1098
1099 client->buffer[0] = 0;
1100 client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1101 client->buf_size, 0);
1102 if (client->msg_size >= 0) {
1103 int rc = crm_ipc_decompress(client);
1104
1105 if (rc != pcmk_rc_ok) {
1106 return pcmk_rc2legacy(rc);
1107 }
1108
1109 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1110 if (!pcmk__valid_ipc_header(header)) {
1111 return -EBADMSG;
1112 }
1113
1114 crm_trace("Received %s IPC event %d size=%u rc=%d text='%.100s'",
1115 client->server_name, header->qb.id, header->qb.size,
1116 client->msg_size,
1117 client->buffer + sizeof(pcmk__ipc_header_t));
1118
1119 } else {
1120 crm_trace("No message received from %s IPC: %s",
1121 client->server_name, pcmk_strerror(client->msg_size));
1122
1123 if (client->msg_size == -EAGAIN) {
1124 return -EAGAIN;
1125 }
1126 }
1127
1128 if (!crm_ipc_connected(client) || client->msg_size == -ENOTCONN) {
1129 crm_err("Connection to %s IPC failed", client->server_name);
1130 }
1131
1132 if (header) {
1133 /* Data excluding the header */
1134 return header->size_uncompressed;
1135 }
1136 return -ENOMSG;
1137}
1138
1139const char *
1141{
1142 CRM_ASSERT(client != NULL);
1143 return client->buffer + sizeof(pcmk__ipc_header_t);
1144}
1145
1146uint32_t
1148{
1149 pcmk__ipc_header_t *header = NULL;
1150
1151 CRM_ASSERT(client != NULL);
1152 if (client->buffer == NULL) {
1153 return 0;
1154 }
1155
1156 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1157 return header->flags;
1158}
1159
1160const char *
1162{
1163 CRM_ASSERT(client != NULL);
1164 return client->server_name;
1165}
1166
1167// \return Standard Pacemaker return code
1168static int
1169internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
1170 ssize_t *bytes)
1171{
1172 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1173 int rc = pcmk_rc_ok;
1174
1175 /* get the reply */
1176 crm_trace("Waiting on reply to %s IPC message %d",
1177 client->server_name, request_id);
1178 do {
1179
1180 *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1181 if (*bytes > 0) {
1182 pcmk__ipc_header_t *hdr = NULL;
1183
1184 rc = crm_ipc_decompress(client);
1185 if (rc != pcmk_rc_ok) {
1186 return rc;
1187 }
1188
1189 hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1190 if (hdr->qb.id == request_id) {
1191 /* Got it */
1192 break;
1193 } else if (hdr->qb.id < request_id) {
1194 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1195
1196 crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1197 crm_log_xml_notice(bad, "OldIpcReply");
1198
1199 } else {
1200 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1201
1202 crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1203 crm_log_xml_notice(bad, "ImpossibleReply");
1204 CRM_ASSERT(hdr->qb.id <= request_id);
1205 }
1206 } else if (!crm_ipc_connected(client)) {
1207 crm_err("%s IPC provider disconnected while waiting for message %d",
1208 client->server_name, request_id);
1209 break;
1210 }
1211
1212 } while (time(NULL) < timeout);
1213
1214 if (*bytes < 0) {
1215 rc = (int) -*bytes; // System errno
1216 }
1217 return rc;
1218}
1219
1233int
1234crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, int32_t ms_timeout,
1235 xmlNode ** reply)
1236{
1237 int rc = 0;
1238 ssize_t qb_rc = 0;
1239 ssize_t bytes = 0;
1240 struct iovec *iov;
1241 static uint32_t id = 0;
1242 static int factor = 8;
1243 pcmk__ipc_header_t *header;
1244
1245 if (client == NULL) {
1246 crm_notice("Can't send IPC request without connection (bug?): %.100s",
1247 message);
1248 return -ENOTCONN;
1249
1250 } else if (!crm_ipc_connected(client)) {
1251 /* Don't even bother */
1252 crm_notice("Can't send %s IPC requests: Connection closed",
1253 client->server_name);
1254 return -ENOTCONN;
1255 }
1256
1257 if (ms_timeout == 0) {
1258 ms_timeout = 5000;
1259 }
1260
1261 if (client->need_reply) {
1262 qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1263 if (qb_rc < 0) {
1264 crm_warn("Sending %s IPC disabled until pending reply received",
1265 client->server_name);
1266 return -EALREADY;
1267
1268 } else {
1269 crm_notice("Sending %s IPC re-enabled after pending reply received",
1270 client->server_name);
1271 client->need_reply = FALSE;
1272 }
1273 }
1274
1275 id++;
1276 CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1277 rc = pcmk__ipc_prepare_iov(id, message, client->max_buf_size, &iov, &bytes);
1278 if (rc != pcmk_rc_ok) {
1279 crm_warn("Couldn't prepare %s IPC request: %s " CRM_XS " rc=%d",
1280 client->server_name, pcmk_rc_str(rc), rc);
1281 return pcmk_rc2legacy(rc);
1282 }
1283
1284 header = iov[0].iov_base;
1285 pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1286
1288 /* Don't look for a synchronous response */
1290 }
1291
1292 if(header->size_compressed) {
1293 if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
1294 crm_notice("Compressed message exceeds %d0%% of configured IPC "
1295 "limit (%u bytes); consider setting PCMK_ipc_buffer to "
1296 "%u or higher",
1297 factor, client->max_buf_size, 2 * client->max_buf_size);
1298 factor++;
1299 }
1300 }
1301
1302 crm_trace("Sending %s IPC request %d of %u bytes using %dms timeout",
1303 client->server_name, header->qb.id, header->qb.size, ms_timeout);
1304
1305 if ((ms_timeout > 0) || !pcmk_is_set(flags, crm_ipc_client_response)) {
1306
1307 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1308
1309 do {
1310 /* @TODO Is this check really needed? Won't qb_ipcc_sendv() return
1311 * an error if it's not connected?
1312 */
1313 if (!crm_ipc_connected(client)) {
1314 goto send_cleanup;
1315 }
1316
1317 qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1318 } while ((qb_rc == -EAGAIN) && (time(NULL) < timeout));
1319
1320 rc = (int) qb_rc; // Negative of system errno, or bytes sent
1321 if (qb_rc <= 0) {
1322 goto send_cleanup;
1323
1325 crm_trace("Not waiting for reply to %s IPC request %d",
1326 client->server_name, header->qb.id);
1327 goto send_cleanup;
1328 }
1329
1330 rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes);
1331 if (rc != pcmk_rc_ok) {
1332 /* We didn't get the reply in time, so disable future sends for now.
1333 * The only alternative would be to close the connection since we
1334 * don't know how to detect and discard out-of-sequence replies.
1335 *
1336 * @TODO Implement out-of-sequence detection
1337 */
1338 client->need_reply = TRUE;
1339 }
1340 rc = (int) bytes; // Negative system errno, or size of reply received
1341
1342 } else {
1343 // No timeout, and client response needed
1344 do {
1345 qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
1346 client->buf_size, -1);
1347 } while ((qb_rc == -EAGAIN) && crm_ipc_connected(client));
1348 rc = (int) qb_rc; // Negative system errno, or size of reply received
1349 }
1350
1351 if (rc > 0) {
1352 pcmk__ipc_header_t *hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1353
1354 crm_trace("Received %d-byte reply %d to %s IPC %d: %.100s",
1355 rc, hdr->qb.id, client->server_name, header->qb.id,
1356 crm_ipc_buffer(client));
1357
1358 if (reply) {
1359 *reply = string2xml(crm_ipc_buffer(client));
1360 }
1361
1362 } else {
1363 crm_trace("No reply to %s IPC %d: rc=%d",
1364 client->server_name, header->qb.id, rc);
1365 }
1366
1367 send_cleanup:
1368 if (!crm_ipc_connected(client)) {
1369 crm_notice("Couldn't send %s IPC request %d: Connection closed "
1370 CRM_XS " rc=%d", client->server_name, header->qb.id, rc);
1371
1372 } else if (rc == -ETIMEDOUT) {
1373 crm_warn("%s IPC request %d failed: %s after %dms " CRM_XS " rc=%d",
1374 client->server_name, header->qb.id, pcmk_strerror(rc),
1375 ms_timeout, rc);
1376 crm_write_blackbox(0, NULL);
1377
1378 } else if (rc <= 0) {
1379 crm_warn("%s IPC request %d failed: %s " CRM_XS " rc=%d",
1380 client->server_name, header->qb.id,
1381 ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1382 }
1383
1385 return rc;
1386}
1387
1388int
1389pcmk__crm_ipc_is_authentic_process(qb_ipcc_connection_t *qb_ipc, int sock, uid_t refuid, gid_t refgid,
1390 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1391{
1392 int ret = 0;
1393 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1394#if defined(HAVE_UCRED)
1395 struct ucred ucred;
1396 socklen_t ucred_len = sizeof(ucred);
1397#endif
1398
1399#ifdef HAVE_QB_IPCC_AUTH_GET
1400 if (qb_ipc && !qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid)) {
1401 goto do_checks;
1402 }
1403#endif
1404
1405#if defined(HAVE_UCRED)
1406 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1407 &ucred, &ucred_len)
1408 && ucred_len == sizeof(ucred)) {
1409 found_pid = ucred.pid; found_uid = ucred.uid; found_gid = ucred.gid;
1410
1411#elif defined(HAVE_SOCKPEERCRED)
1412 struct sockpeercred sockpeercred;
1413 socklen_t sockpeercred_len = sizeof(sockpeercred);
1414
1415 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1416 &sockpeercred, &sockpeercred_len)
1417 && sockpeercred_len == sizeof(sockpeercred_len)) {
1418 found_pid = sockpeercred.pid;
1419 found_uid = sockpeercred.uid; found_gid = sockpeercred.gid;
1420
1421#elif defined(HAVE_GETPEEREID)
1422 if (!getpeereid(sock, &found_uid, &found_gid)) {
1423 found_pid = PCMK__SPECIAL_PID; /* cannot obtain PID (FreeBSD) */
1424
1425#elif defined(HAVE_GETPEERUCRED)
1426 ucred_t *ucred;
1427 if (!getpeerucred(sock, &ucred)) {
1428 errno = 0;
1429 found_pid = ucred_getpid(ucred);
1430 found_uid = ucred_geteuid(ucred); found_gid = ucred_getegid(ucred);
1431 ret = -errno;
1432 ucred_free(ucred);
1433 if (ret) {
1434 return (ret < 0) ? ret : -pcmk_err_generic;
1435 }
1436
1437#else
1438# error "No way to authenticate a Unix socket peer"
1439 errno = 0;
1440 if (0) {
1441#endif
1442#ifdef HAVE_QB_IPCC_AUTH_GET
1443 do_checks:
1444#endif
1445 if (gotpid != NULL) {
1446 *gotpid = found_pid;
1447 }
1448 if (gotuid != NULL) {
1449 *gotuid = found_uid;
1450 }
1451 if (gotgid != NULL) {
1452 *gotgid = found_gid;
1453 }
1454 if (found_uid == 0 || found_uid == refuid || found_gid == refgid) {
1455 ret = 0;
1456 } else {
1458 }
1459 } else {
1460 ret = (errno > 0) ? errno : pcmk_rc_error;
1461 }
1462 return ret;
1463}
1464
1465int
1466crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
1467 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1468{
1469 int ret = pcmk__crm_ipc_is_authentic_process(NULL, sock, refuid, refgid,
1470 gotpid, gotuid, gotgid);
1471
1472 /* The old function had some very odd return codes*/
1473 if (ret == 0) {
1474 return 1;
1475 } else if (ret == pcmk_rc_ipc_unauthorized) {
1476 return 0;
1477 } else {
1478 return pcmk_rc2legacy(ret);
1479 }
1480}
1481
1482int
1484 gid_t refgid, pid_t *gotpid)
1485{
1486 static char last_asked_name[PATH_MAX / 2] = ""; /* log spam prevention */
1487 int fd;
1488 int rc = pcmk_rc_ipc_unresponsive;
1489 int auth_rc = 0;
1490 int32_t qb_rc;
1491 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1492 qb_ipcc_connection_t *c;
1493#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1494 struct pollfd pollfd = { 0, };
1495 int poll_rc;
1496
1497 c = qb_ipcc_connect_async(name, 0,
1498 &(pollfd.fd));
1499#else
1500 c = qb_ipcc_connect(name, 0);
1501#endif
1502 if (c == NULL) {
1503 crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1505 goto bail;
1506 }
1507#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1508 pollfd.events = POLLIN;
1509 do {
1510 poll_rc = poll(&pollfd, 1, 2000);
1511 } while ((poll_rc == -1) && (errno == EINTR));
1512 if ((poll_rc <= 0) || (qb_ipcc_connect_continue(c) != 0)) {
1513 crm_info("Could not connect to %s IPC: %s", name,
1514 (poll_rc == 0)?"timeout":strerror(errno));
1516 if (poll_rc > 0) {
1517 c = NULL; // qb_ipcc_connect_continue cleaned up for us
1518 }
1519 goto bail;
1520 }
1521#endif
1522
1523 qb_rc = qb_ipcc_fd_get(c, &fd);
1524 if (qb_rc != 0) {
1525 rc = (int) -qb_rc; // System errno
1526 crm_err("Could not get fd from %s IPC: %s " CRM_XS " rc=%d",
1527 name, pcmk_rc_str(rc), rc);
1528 goto bail;
1529 }
1530
1531 auth_rc = pcmk__crm_ipc_is_authentic_process(c, fd, refuid, refgid, &found_pid,
1532 &found_uid, &found_gid);
1533 if (auth_rc == pcmk_rc_ipc_unauthorized) {
1534 crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1535 " process %lld (uid: %lld, gid: %lld)",
1536 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1537 (long long) found_uid, (long long) found_gid);
1539 goto bail;
1540 }
1541
1542 if (auth_rc != pcmk_rc_ok) {
1543 rc = auth_rc;
1544 crm_err("Could not get peer credentials from %s IPC: %s "
1545 CRM_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1546 goto bail;
1547 }
1548
1549 if (gotpid != NULL) {
1550 *gotpid = found_pid;
1551 }
1552
1553 rc = pcmk_rc_ok;
1554 if ((found_uid != refuid || found_gid != refgid)
1555 && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1556 if ((found_uid == 0) && (refuid != 0)) {
1557 crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1558 " credentials are %lld:%lld, hazard of violating"
1559 " the least privilege principle",
1560 name, (long long) refuid, (long long) refgid);
1561 } else {
1562 crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1563 " expected credentials are %lld:%lld, which may"
1564 " mean a different set of privileges than expected",
1565 name, (long long) found_uid, (long long) found_gid,
1566 (long long) refuid, (long long) refgid);
1567 }
1568 memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1569 }
1570
1571bail:
1572 if (c != NULL) {
1573 qb_ipcc_disconnect(c);
1574 }
1575 return rc;
1576}
const char * name
Definition cib.c:24
void pcmk__xe_add_node(xmlNode *xml, const char *node, int nodeid)
Definition nodes.c:15
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:873
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:126
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:121
A dumping ground.
#define CRM_SYSTEM_CRMD
Definition crm.h:105
#define CRM_SYSTEM_MCP
Definition crm.h:110
#define CRM_OP_RM_NODE_CACHE
Definition crm.h:157
char * crm_system_name
Definition utils.c:51
#define CRM_SYSTEM_PENGINE
Definition crm.h:107
#define PCMK__ATTRD_CMD_PEER_REMOVE
#define PCMK__XA_TASK
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:117
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: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:274
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:165
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:395
void crm_ipc_destroy(crm_ipc_t *client)
Definition ipc_client.c:955
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.
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance.
Definition ipc_client.c:565
const char * crm_ipc_name(crm_ipc_t *client)
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:489
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition ipc_client.c:639
long crm_ipc_read(crm_ipc_t *client)
int crm_ipc_get_fd(crm_ipc_t *client)
Definition ipc_client.c:981
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:146
bool crm_ipc_connected(crm_ipc_t *client)
Definition ipc_client.c:995
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition ipc_client.c:867
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:243
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:942
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
Definition ipc_client.c:202
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: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.
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:283
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop)
Definition ipc_client.c:428
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:820
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:767
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:616
#define PCMK__SPECIAL_PID_AS_0(p)
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
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:580
#define PCMK__SPECIAL_PID
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
#define crm_info(fmt, args...)
Definition logging.h:378
void crm_write_blackbox(int nsig, const struct qb_log_callsite *callsite)
Definition logging.c:500
#define crm_warn(fmt, args...)
Definition logging.h:376
#define CRM_XS
Definition logging.h:55
#define CRM_LOG_ASSERT(expr)
Definition logging.h:219
#define crm_notice(fmt, args...)
Definition logging.h:377
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:319
#define CRM_CHECK(expr, failure_action)
Definition logging.h:235
#define crm_debug(fmt, args...)
Definition logging.h:380
#define crm_err(fmt, args...)
Definition logging.h:375
#define crm_log_xml_trace(xml, text)
Definition logging.h:389
#define crm_trace(fmt, args...)
Definition logging.h:381
#define crm_log_xml_notice(xml, text)
Definition logging.h:386
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:33
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:940
#define XML_ATTR_UNAME
Definition msg_xml.h:170
#define T_ATTRD
Definition msg_xml.h:98
#define F_ORIG
Definition msg_xml.h:70
#define F_TYPE
Definition msg_xml.h:82
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:302
unsigned int timeout
Definition pcmk_fence.c:32
#define ENODATA
char * strerror(int errnum)
const char * bz2_strerror(int rc)
Definition results.c:841
const char * pcmk_strerror(int rc)
Definition results.c:148
#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:488
@ CRM_EX_DISCONNECT
Lost connection to something.
Definition results.h:270
@ pcmk_rc_ok
Definition results.h:151
@ pcmk_rc_ipc_unauthorized
Definition results.h:129
@ pcmk_rc_error
Definition results.h:147
@ pcmk_rc_ipc_unresponsive
Definition results.h:128
#define pcmk_ok
Definition results.h:68
int pcmk_rc2legacy(int rc)
Definition results.c:533
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:546
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:831
void free_xml(xmlNode *child)
Definition xml.c:813
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:677