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