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