pacemaker  2.1.6-802a72226b
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(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 
46 int
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) {
60  pcmk_free_ipc_api(*api);
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 
77  case pcmk_ipc_controld:
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) {
98  pcmk_free_ipc_api(*api);
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 
123 static void
124 free_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 
145 void
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 
162 static void
163 ipc_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 
201 void
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 
242 const char *
243 pcmk_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 
255  case pcmk_ipc_controld:
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 
264  case pcmk_ipc_pacemakerd:
265  return for_log? "launcher" : CRM_SYSTEM_MCP;
266 
267  case pcmk_ipc_schedulerd:
268  return for_log? "scheduler" : CRM_SYSTEM_PENGINE;
269 
270  default:
271  return for_log? "Pacemaker" : NULL;
272  }
273 }
274 
282 bool
284 {
285  return (api != NULL) && crm_ipc_connected(api->ipc);
286 }
287 
299 static bool
300 call_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 
325 static int
326 dispatch_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 
366 static int
367 dispatch_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 
394 int
395 pcmk_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 
427 void
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
441 static int
442 connect_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
465 static int
466 connect_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 
488 int
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 
564 void
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 
615 void
617  void *user_data)
618 {
619  if (api == NULL) {
620  return;
621  }
622  api->cb = cb;
623  api->user_data = user_data;
624 }
625 
638 int
639 pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
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 
720 static xmlNode *
721 create_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 
736  case pcmk_ipc_controld:
737  case pcmk_ipc_fenced:
738  case pcmk_ipc_pacemakerd:
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:
749  case pcmk_ipc_schedulerd:
750  break;
751  }
752  return request;
753 }
754 
766 int
767 pcmk_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 
795 struct 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 
819 crm_ipc_t *
820 crm_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 
866 bool
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 
941 void
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 
954 void
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 
980 int
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 
994 bool
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 
1026 int
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
1043 static int
1044 crm_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 
1090 long
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 
1139 const char *
1141 {
1142  CRM_ASSERT(client != NULL);
1143  return client->buffer + sizeof(pcmk__ipc_header_t);
1144 }
1145 
1146 uint32_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 
1160 const char *
1162 {
1163  CRM_ASSERT(client != NULL);
1164  return client->server_name;
1165 }
1166 
1167 // \return Standard Pacemaker return code
1168 static int
1169 internal_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 
1233 int
1234 crm_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 
1324  } else if (!pcmk_is_set(flags, crm_ipc_client_response)) {
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 
1384  pcmk_free_ipc_event(iov);
1385  return rc;
1386 }
1387 
1388 int
1389 pcmk__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 
1465 int
1466 crm_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 
1482 int
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 
1571 bail:
1572  if (c != NULL) {
1573  qb_ipcc_disconnect(c);
1574  }
1575  return rc;
1576 }
#define T_ATTRD
Definition: msg_xml.h:98
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:235
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
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:82
#define crm_notice(fmt, args...)
Definition: logging.h:379
const char * pcmk_strerror(int rc)
Definition: results.c:148
const char * bz2_strerror(int rc)
Definition: results.c:841
enum pcmk_ipc_dispatch dispatch_type
Scheduler.
Definition: ipc.h:76
#define PCMK__ATTRD_CMD_PEER_REMOVE
Definition: crm_internal.h:104
int pcmk_rc2legacy(int rc)
Definition: results.c:533
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1091
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
Definition: ipc_client.c:202
const char * name
Definition: cib.c:24
Launcher.
Definition: ipc.h:75
#define PCMK__XA_TASK
Definition: crm_internal.h:87
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__schedulerd_api_methods(void)
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1140
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
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:33
#define PCMK__SPECIAL_PID_AS_0(p)
Definition: ipc_internal.h:61
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
#define pcmk_err_generic
Definition: results.h:71
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
#define PCMK__SPECIAL_PID
Definition: ipc_internal.h:49
char * crm_system_name
Definition: utils.c:51
enum crm_exit_e crm_exit_t
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:955
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
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition: ipc_client.c:639
int pcmk_daemon_user(uid_t *uid, gid_t *gid)
Get user and group IDs of pacemaker daemon user.
Definition: utils.c:126
struct pcmk__ipc_header_s pcmk__ipc_header_t
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:488
char * strerror(int errnum)
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:981
xmlNode * string2xml(const char *input)
Definition: xml.c:831
int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid)
Definition: ipc_client.c:1483
#define CRM_SYSTEM_MCP
Definition: crm.h:110
struct qb_ipc_response_header qb
CIB manager.
Definition: ipc.h:71
Caller will poll and dispatch IPC.
Definition: ipc.h:90
#define crm_warn(fmt, args...)
Definition: logging.h:378
pcmk_ipc_server
Available IPC interfaces.
Definition: ipc.h:69
#define crm_debug(fmt, args...)
Definition: logging.h:382
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:867
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
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:165
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
pcmk_ipc_callback_t cb
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__attrd_api_methods(void)
Definition: ipc_attrd.c:117
#define crm_trace(fmt, args...)
Definition: logging.h:383
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
void crm_xml_set_id(xmlNode *xml, const char *format,...) G_GNUC_PRINTF(2
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
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc_client.c:1147
#define CRM_SYSTEM_PENGINE
Definition: crm.h:107
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
Definition: ipc_internal.h:214
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance.
Definition: ipc_client.c:565
G_GNUC_INTERNAL bool pcmk__valid_ipc_header(const pcmk__ipc_header_t *header)
Definition: ipc_common.c:81
#define XML_ATTR_UNAME
Definition: msg_xml.h:170
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
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:677
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:942
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:940
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:1234
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:546
#define F_ORIG
Definition: msg_xml.h:70
void free_xml(xmlNode *child)
Definition: xml.c:813
void pcmk_free_ipc_event(struct iovec *event)
Free an I/O vector created by pcmk__ipc_prepare_iov()
Definition: ipc_server.c:274
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
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:1389
int(* post_connect)(pcmk_ipc_api_t *api)
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
void crm_write_blackbox(int nsig, const struct qb_log_callsite *callsite)
Definition: logging.c:500
G_GNUC_INTERNAL unsigned int pcmk__ipc_buffer_size(unsigned int max)
Definition: ipc_common.c:31
#define CRM_SYSTEM_CRMD
Definition: crm.h:105
#define CRM_XS
Definition: logging.h:55
#define CRM_OP_RM_NODE_CACHE
Definition: crm.h:157
pcmk_ipc_dispatch
How IPC replies should be dispatched.
Definition: ipc.h:88
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
Definition: ipc.h:80
#define ENODATA
Definition: portability.h:145
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:995
Attach IPC to GMainLoop for dispatch.
Definition: ipc.h:89
Termination of IPC connection.
Definition: ipc.h:82
mainloop_io_t * mainloop_io
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:319
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
Executor.
Definition: ipc.h:73
Controller.
Definition: ipc.h:72
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:207
#define crm_err(fmt, args...)
Definition: logging.h:377
#define CRM_ASSERT(expr)
Definition: results.h:42
Sending a command will wait for any reply.
Definition: ipc.h:91
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop)
Definition: ipc_client.c:428
#define crm_log_xml_notice(xml, text)
Definition: logging.h:388
Lost connection to something.
Definition: results.h:270
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1027
void(* free_data)(void *api_data)
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
Fencer.
Definition: ipc.h:74
#define pcmk_ok
Definition: results.h:68
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active.
Definition: ipc_client.c:283
IPC interface to Pacemaker daemons.
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
#define crm_log_xml_trace(xml, text)
Definition: logging.h:391
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__controld_api_methods(void)
Definition: ipc_controld.c:296
pcmk__ipc_methods_t * cmds
void pcmk__xe_add_node(xmlNode *xml, const char *node, int nodeid)
Definition: nodes.c:15
void(* post_disconnect)(pcmk_ipc_api_t *api)
Attribute manager.
Definition: ipc.h:70
enum pcmk_ipc_server server
crm_ipc_flags
Definition: ipc.h:144
unsigned int timeout
Definition: pcmk_fence.c:32
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition: ipc.h:43
#define crm_info(fmt, args...)
Definition: logging.h:380
uint64_t flags
Definition: remote.c:215
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:84
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:1466
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc_client.c:1161