pacemaker  3.0.0-d8340737c4
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 #include <sys/socket.h>
14 #elif defined(HAVE_GETPEERUCRED)
15 #include <ucred.h>
16 #endif
17 
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <errno.h>
21 #include <bzlib.h>
22 
23 #include <crm/crm.h> /* indirectly: pcmk_err_generic */
24 #include <crm/common/xml.h>
25 #include <crm/common/ipc.h>
27 #include "crmcommon_private.h"
28 
29 static int is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
30  uid_t refuid, gid_t refgid, pid_t *gotpid,
31  uid_t *gotuid, gid_t *gotgid);
32 
45 int
47 {
48  if (api == NULL) {
49  return EINVAL;
50  }
51 
52  *api = calloc(1, sizeof(pcmk_ipc_api_t));
53  if (*api == NULL) {
54  return errno;
55  }
56 
57  (*api)->server = server;
58  if (pcmk_ipc_name(*api, false) == NULL) {
59  pcmk_free_ipc_api(*api);
60  *api = NULL;
61  return EOPNOTSUPP;
62  }
63 
64  (*api)->ipc_size_max = 0;
65 
66  // Set server methods and max_size (if not default)
67  switch (server) {
68  case pcmk_ipc_attrd:
69  (*api)->cmds = pcmk__attrd_api_methods();
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  default: // pcmk_ipc_unknown
97  pcmk_free_ipc_api(*api);
98  *api = NULL;
99  return EINVAL;
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  if (for_log) {
253  const char *name = pcmk__server_log_name(api->server);
254 
255  return pcmk__s(name, "Pacemaker");
256  }
257  switch (api->server) {
258  // These servers do not have pcmk_ipc_api_t implementations yet
259  case pcmk_ipc_based:
260  case pcmk_ipc_execd:
261  case pcmk_ipc_fenced:
262  return NULL;
263 
264  default:
265  return pcmk__server_ipc_name(api->server);
266  }
267 }
268 
276 bool
278 {
279  return (api != NULL) && crm_ipc_connected(api->ipc);
280 }
281 
293 static bool
294 call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
295 {
296  crm_log_xml_trace(message, "ipc-received");
297  if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
298  return api->cmds->dispatch(api, message);
299  }
300 
301  return false;
302 }
303 
319 static int
320 dispatch_ipc_data(const char *buffer, pcmk_ipc_api_t *api)
321 {
322  bool more = false;
323  xmlNode *msg;
324 
325  if (buffer == NULL) {
326  crm_warn("Empty message received from %s IPC",
327  pcmk_ipc_name(api, true));
328  return ENOMSG;
329  }
330 
331  msg = pcmk__xml_parse(buffer);
332  if (msg == NULL) {
333  crm_warn("Malformed message received from %s IPC",
334  pcmk_ipc_name(api, true));
335  return EPROTO;
336  }
337 
338  more = call_api_dispatch(api, msg);
339  pcmk__xml_free(msg);
340 
341  if (more) {
342  return EINPROGRESS;
343  } else {
344  return pcmk_rc_ok;
345  }
346 }
347 
360 static int
361 dispatch_ipc_source_data(const char *buffer, ssize_t length, gpointer user_data)
362 {
363  pcmk_ipc_api_t *api = user_data;
364 
365  CRM_CHECK(api != NULL, return 0);
366  dispatch_ipc_data(buffer, api);
367  return 0;
368 }
369 
388 int
389 pcmk_poll_ipc(const pcmk_ipc_api_t *api, int timeout_ms)
390 {
391  int rc;
392  struct pollfd pollfd = { 0, };
393 
394  if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
395  return EINVAL;
396  }
397 
398  rc = pcmk__ipc_fd(api->ipc, &(pollfd.fd));
399  if (rc != pcmk_rc_ok) {
400  crm_debug("Could not obtain file descriptor for %s IPC: %s",
401  pcmk_ipc_name(api, true), pcmk_rc_str(rc));
402  return rc;
403  }
404 
405  pollfd.events = POLLIN;
406  rc = poll(&pollfd, 1, timeout_ms);
407  if (rc < 0) {
408  /* Some UNIX systems return negative and set EAGAIN for failure to
409  * allocate memory; standardize the return code in that case
410  */
411  return (errno == EAGAIN)? ENOMEM : errno;
412  } else if (rc == 0) {
413  return EAGAIN;
414  }
415  return pcmk_rc_ok;
416 }
417 
428 void
430 {
431  if (api == NULL) {
432  return;
433  }
434  while (crm_ipc_ready(api->ipc) > 0) {
435  if (crm_ipc_read(api->ipc) > 0) {
436  dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
437  }
438  }
439 }
440 
441 // \return Standard Pacemaker return code
442 static int
443 connect_with_main_loop(pcmk_ipc_api_t *api)
444 {
445  int rc;
446 
447  struct ipc_client_callbacks callbacks = {
448  .dispatch = dispatch_ipc_source_data,
449  .destroy = ipc_post_disconnect,
450  };
451 
452  rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
453  &callbacks, &(api->mainloop_io));
454  if (rc != pcmk_rc_ok) {
455  return rc;
456  }
457  crm_debug("Connected to %s IPC (attached to main loop)",
458  pcmk_ipc_name(api, true));
459  /* After this point, api->mainloop_io owns api->ipc, so api->ipc
460  * should not be explicitly freed.
461  */
462  return pcmk_rc_ok;
463 }
464 
465 // \return Standard Pacemaker return code
466 static int
467 connect_without_main_loop(pcmk_ipc_api_t *api)
468 {
469  int rc = pcmk__connect_generic_ipc(api->ipc);
470 
471  if (rc != pcmk_rc_ok) {
472  crm_ipc_close(api->ipc);
473  } else {
474  crm_debug("Connected to %s IPC (without main loop)",
475  pcmk_ipc_name(api, true));
476  }
477  return rc;
478 }
479 
490 int
492  int attempts)
493 {
494  int rc = pcmk_rc_ok;
495 
496  if ((api == NULL) || (attempts < 1)) {
497  return EINVAL;
498  }
499 
500  if (api->ipc == NULL) {
501  api->ipc = crm_ipc_new(pcmk_ipc_name(api, false), api->ipc_size_max);
502  if (api->ipc == NULL) {
503  return ENOMEM;
504  }
505  }
506 
507  if (crm_ipc_connected(api->ipc)) {
508  crm_trace("Already connected to %s", pcmk_ipc_name(api, true));
509  return pcmk_rc_ok;
510  }
511 
512  api->dispatch_type = dispatch_type;
513 
514  crm_debug("Attempting connection to %s (up to %d time%s)",
515  pcmk_ipc_name(api, true), attempts, pcmk__plural_s(attempts));
516  for (int remaining = attempts - 1; remaining >= 0; --remaining) {
517  switch (dispatch_type) {
519  rc = connect_with_main_loop(api);
520  break;
521 
524  rc = connect_without_main_loop(api);
525  break;
526  }
527 
528  if ((remaining == 0) || ((rc != EAGAIN) && (rc != EALREADY))) {
529  break; // Result is final
530  }
531 
532  // Retry after soft error (interrupted by signal, etc.)
533  pcmk__sleep_ms((attempts - remaining) * 500);
534  crm_debug("Re-attempting connection to %s (%d attempt%s remaining)",
535  pcmk_ipc_name(api, true), remaining,
536  pcmk__plural_s(remaining));
537  }
538 
539  if (rc != pcmk_rc_ok) {
540  return rc;
541  }
542 
543  if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
544  rc = api->cmds->post_connect(api);
545  if (rc != pcmk_rc_ok) {
546  crm_ipc_close(api->ipc);
547  }
548  }
549  return rc;
550 }
551 
560 int
562 {
563  int rc = pcmk__connect_ipc(api, dispatch_type, 2);
564 
565  if (rc != pcmk_rc_ok) {
566  crm_err("Connection to %s failed: %s",
567  pcmk_ipc_name(api, true), pcmk_rc_str(rc));
568  }
569  return rc;
570 }
571 
583 void
585 {
586  if ((api == NULL) || (api->ipc == NULL)) {
587  return;
588  }
589  switch (api->dispatch_type) {
591  {
592  mainloop_io_t *mainloop_io = api->mainloop_io;
593 
594  // Make sure no code with access to api can use these again
595  api->mainloop_io = NULL;
596  api->ipc = NULL;
597 
598  mainloop_del_ipc_client(mainloop_io);
599  // After this point api might have already been freed
600  }
601  break;
602 
605  {
606  crm_ipc_t *ipc = api->ipc;
607 
608  // Make sure no code with access to api can use ipc again
609  api->ipc = NULL;
610 
611  // This should always be the case already, but to be safe
612  api->free_on_disconnect = false;
613 
614  crm_ipc_close(ipc);
615  crm_ipc_destroy(ipc);
616  ipc_post_disconnect(api);
617  }
618  break;
619  }
620 }
621 
634 void
636  void *user_data)
637 {
638  if (api == NULL) {
639  return;
640  }
641  api->cb = cb;
642  api->user_data = user_data;
643 }
644 
657 int
658 pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
659 {
660  int rc;
661  xmlNode *reply = NULL;
663 
664  if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
665  return EINVAL;
666  }
667  crm_log_xml_trace(request, "ipc-sent");
668 
669  // Synchronous dispatch requires waiting for a reply
671  && (api->cmds != NULL)
672  && (api->cmds->reply_expected != NULL)
673  && (api->cmds->reply_expected(api, request))) {
675  }
676 
677  // The 0 here means a default timeout of 5 seconds
678  rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
679 
680  if (rc < 0) {
681  return pcmk_legacy2rc(rc);
682  } else if (rc == 0) {
683  return ENODATA;
684  }
685 
686  // With synchronous dispatch, we dispatch any reply now
687  if (reply != NULL) {
688  bool more = call_api_dispatch(api, reply);
689 
690  pcmk__xml_free(reply);
691 
692  while (more) {
693  rc = crm_ipc_read(api->ipc);
694 
695  if (rc == -EAGAIN) {
696  continue;
697  } else if (rc == -ENOMSG || rc == pcmk_ok) {
698  return pcmk_rc_ok;
699  } else if (rc < 0) {
700  return -rc;
701  }
702 
703  rc = dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
704 
705  if (rc == pcmk_rc_ok) {
706  more = false;
707  } else if (rc == EINPROGRESS) {
708  more = true;
709  } else {
710  continue;
711  }
712  }
713  }
714  return pcmk_rc_ok;
715 }
716 
739 static xmlNode *
740 create_purge_node_request(const pcmk_ipc_api_t *api, const char *node_name,
741  uint32_t nodeid)
742 {
743  xmlNode *request = NULL;
744  const char *client = crm_system_name? crm_system_name : "client";
745 
746  switch (api->server) {
747  case pcmk_ipc_attrd:
748  request = pcmk__xe_create(NULL, __func__);
752  pcmk__xe_set_bool_attr(request, PCMK__XA_REAP, true);
753  pcmk__xe_add_node(request, node_name, nodeid);
754  break;
755 
756  case pcmk_ipc_controld:
757  case pcmk_ipc_fenced:
758  case pcmk_ipc_pacemakerd:
759  request = pcmk__new_request(api->server, client, NULL,
760  pcmk_ipc_name(api, false),
761  CRM_OP_RM_NODE_CACHE, NULL);
762  if (nodeid > 0) {
763  crm_xml_add_ll(request, PCMK_XA_ID, (long long) nodeid);
764  }
765  crm_xml_add(request, PCMK_XA_UNAME, node_name);
766  break;
767 
768  case pcmk_ipc_based:
769  case pcmk_ipc_execd:
770  case pcmk_ipc_schedulerd:
771  break;
772 
773  default: // pcmk_ipc_unknown (shouldn't be possible)
774  return NULL;
775  }
776  return request;
777 }
778 
790 int
791 pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
792 {
793  int rc = 0;
794  xmlNode *request = NULL;
795 
796  if (api == NULL) {
797  return EINVAL;
798  }
799  if ((node_name == NULL) && (nodeid == 0)) {
800  return EINVAL;
801  }
802 
803  request = create_purge_node_request(api, node_name, nodeid);
804  if (request == NULL) {
805  return EOPNOTSUPP;
806  }
807  rc = pcmk__send_ipc_request(api, request);
808  pcmk__xml_free(request);
809 
810  crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
811  pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
812  return rc;
813 }
814 
815 /*
816  * Generic IPC API (to eventually be deprecated as public API and made internal)
817  */
818 
819 struct crm_ipc_s {
820  struct pollfd pfd;
821  unsigned int max_buf_size; // maximum bytes we can send or receive over IPC
822  unsigned int buf_size; // size of allocated buffer
823  int msg_size;
824  int need_reply;
825  char *buffer;
826  char *server_name; // server IPC name being connected to
827  qb_ipcc_connection_t *ipc;
828 };
829 
843 crm_ipc_t *
844 crm_ipc_new(const char *name, size_t max_size)
845 {
846  crm_ipc_t *client = NULL;
847 
848  client = calloc(1, sizeof(crm_ipc_t));
849  if (client == NULL) {
850  crm_err("Could not create IPC connection: %s", strerror(errno));
851  return NULL;
852  }
853 
854  client->server_name = strdup(name);
855  if (client->server_name == NULL) {
856  crm_err("Could not create %s IPC connection: %s",
857  name, strerror(errno));
858  free(client);
859  return NULL;
860  }
861  client->buf_size = pcmk__ipc_buffer_size(max_size);
862  client->buffer = malloc(client->buf_size);
863  if (client->buffer == NULL) {
864  crm_err("Could not create %s IPC connection: %s",
865  name, strerror(errno));
866  free(client->server_name);
867  free(client);
868  return NULL;
869  }
870 
871  /* Clients initiating connection pick the max buf size */
872  client->max_buf_size = client->buf_size;
873 
874  client->pfd.fd = -1;
875  client->pfd.events = POLLIN;
876  client->pfd.revents = 0;
877 
878  return client;
879 }
880 
889 int
891 {
892  uid_t cl_uid = 0;
893  gid_t cl_gid = 0;
894  pid_t found_pid = 0;
895  uid_t found_uid = 0;
896  gid_t found_gid = 0;
897  int rc = pcmk_rc_ok;
898 
899  if (ipc == NULL) {
900  return EINVAL;
901  }
902 
903  ipc->need_reply = FALSE;
904  ipc->ipc = qb_ipcc_connect(ipc->server_name, ipc->buf_size);
905  if (ipc->ipc == NULL) {
906  return errno;
907  }
908 
909  rc = qb_ipcc_fd_get(ipc->ipc, &ipc->pfd.fd);
910  if (rc < 0) { // -errno
911  crm_ipc_close(ipc);
912  return -rc;
913  }
914 
915  rc = pcmk_daemon_user(&cl_uid, &cl_gid);
916  rc = pcmk_legacy2rc(rc);
917  if (rc != pcmk_rc_ok) {
918  crm_ipc_close(ipc);
919  return rc;
920  }
921 
922  rc = is_ipc_provider_expected(ipc->ipc, ipc->pfd.fd, cl_uid, cl_gid,
923  &found_pid, &found_uid, &found_gid);
924  if (rc != pcmk_rc_ok) {
925  if (rc == pcmk_rc_ipc_unauthorized) {
926  crm_info("%s IPC provider authentication failed: process %lld has "
927  "uid %lld (expected %lld) and gid %lld (expected %lld)",
928  ipc->server_name,
929  (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
930  (long long) found_uid, (long long) cl_uid,
931  (long long) found_gid, (long long) cl_gid);
932  }
933  crm_ipc_close(ipc);
934  return rc;
935  }
936 
937  ipc->max_buf_size = qb_ipcc_get_buffer_size(ipc->ipc);
938  if (ipc->max_buf_size > ipc->buf_size) {
939  free(ipc->buffer);
940  ipc->buffer = calloc(ipc->max_buf_size, sizeof(char));
941  if (ipc->buffer == NULL) {
942  rc = errno;
943  crm_ipc_close(ipc);
944  return rc;
945  }
946  ipc->buf_size = ipc->max_buf_size;
947  }
948 
949  return pcmk_rc_ok;
950 }
951 
952 void
954 {
955  if (client) {
956  if (client->ipc) {
957  qb_ipcc_connection_t *ipc = client->ipc;
958 
959  client->ipc = NULL;
960  qb_ipcc_disconnect(ipc);
961  }
962  }
963 }
964 
965 void
967 {
968  if (client) {
969  if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
970  crm_notice("Destroying active %s IPC connection",
971  client->server_name);
972  /* The next line is basically unsafe
973  *
974  * If this connection was attached to mainloop and mainloop is active,
975  * the 'disconnected' callback will end up back here and we'll end
976  * up free'ing the memory twice - something that can still happen
977  * even without this if we destroy a connection and it closes before
978  * we call exit
979  */
980  /* crm_ipc_close(client); */
981  } else {
982  crm_trace("Destroying inactive %s IPC connection",
983  client->server_name);
984  }
985  free(client->buffer);
986  free(client->server_name);
987  free(client);
988  }
989 }
990 
1000 int
1001 pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
1002 {
1003  if ((ipc == NULL) || (fd == NULL)) {
1004  return EINVAL;
1005  }
1006  if ((ipc->ipc == NULL) || (ipc->pfd.fd < 0)) {
1007  return ENOTCONN;
1008  }
1009  *fd = ipc->pfd.fd;
1010  return pcmk_rc_ok;
1011 }
1012 
1013 int
1015 {
1016  int fd = -1;
1017 
1018  if (pcmk__ipc_fd(client, &fd) != pcmk_rc_ok) {
1019  crm_err("Could not obtain file descriptor for %s IPC",
1020  ((client == NULL)? "unspecified" : client->server_name));
1021  errno = EINVAL;
1022  return -EINVAL;
1023  }
1024  return fd;
1025 }
1026 
1027 bool
1029 {
1030  bool rc = FALSE;
1031 
1032  if (client == NULL) {
1033  crm_trace("No client");
1034  return FALSE;
1035 
1036  } else if (client->ipc == NULL) {
1037  crm_trace("No connection");
1038  return FALSE;
1039 
1040  } else if (client->pfd.fd < 0) {
1041  crm_trace("Bad descriptor");
1042  return FALSE;
1043  }
1044 
1045  rc = qb_ipcc_is_connected(client->ipc);
1046  if (rc == FALSE) {
1047  client->pfd.fd = -EINVAL;
1048  }
1049  return rc;
1050 }
1051 
1059 int
1061 {
1062  int rc;
1063 
1064  pcmk__assert(client != NULL);
1065 
1066  if (!crm_ipc_connected(client)) {
1067  return -ENOTCONN;
1068  }
1069 
1070  client->pfd.revents = 0;
1071  rc = poll(&(client->pfd), 1, 0);
1072  return (rc < 0)? -errno : rc;
1073 }
1074 
1075 // \return Standard Pacemaker return code
1076 static int
1077 crm_ipc_decompress(crm_ipc_t * client)
1078 {
1079  pcmk__ipc_header_t *header = (pcmk__ipc_header_t *)(void*)client->buffer;
1080 
1081  if (header->size_compressed) {
1082  int rc = 0;
1083  unsigned int size_u = 1 + header->size_uncompressed;
1084  /* never let buf size fall below our max size required for ipc reads. */
1085  unsigned int new_buf_size = QB_MAX((sizeof(pcmk__ipc_header_t) + size_u), client->max_buf_size);
1086  char *uncompressed = pcmk__assert_alloc(1, new_buf_size);
1087 
1088  crm_trace("Decompressing message data %u bytes into %u bytes",
1089  header->size_compressed, size_u);
1090 
1091  rc = BZ2_bzBuffToBuffDecompress(uncompressed + sizeof(pcmk__ipc_header_t), &size_u,
1092  client->buffer + sizeof(pcmk__ipc_header_t), header->size_compressed, 1, 0);
1093  rc = pcmk__bzlib2rc(rc);
1094 
1095  if (rc != pcmk_rc_ok) {
1096  crm_err("Decompression failed: %s " QB_XS " rc=%d",
1097  pcmk_rc_str(rc), rc);
1098  free(uncompressed);
1099  return rc;
1100  }
1101 
1102  pcmk__assert(size_u == header->size_uncompressed);
1103 
1104  memcpy(uncompressed, client->buffer, sizeof(pcmk__ipc_header_t)); /* Preserve the header */
1105  header = (pcmk__ipc_header_t *)(void*)uncompressed;
1106 
1107  free(client->buffer);
1108  client->buf_size = new_buf_size;
1109  client->buffer = uncompressed;
1110  }
1111 
1112  pcmk__assert(client->buffer[sizeof(pcmk__ipc_header_t)
1113  + header->size_uncompressed - 1] == 0);
1114  return pcmk_rc_ok;
1115 }
1116 
1117 long
1119 {
1120  pcmk__ipc_header_t *header = NULL;
1121 
1122  pcmk__assert((client != NULL) && (client->ipc != NULL)
1123  && (client->buffer != NULL));
1124 
1125  client->buffer[0] = 0;
1126  client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1127  client->buf_size, 0);
1128  if (client->msg_size >= 0) {
1129  int rc = crm_ipc_decompress(client);
1130 
1131  if (rc != pcmk_rc_ok) {
1132  return pcmk_rc2legacy(rc);
1133  }
1134 
1135  header = (pcmk__ipc_header_t *)(void*)client->buffer;
1136  if (!pcmk__valid_ipc_header(header)) {
1137  return -EBADMSG;
1138  }
1139 
1140  crm_trace("Received %s IPC event %d size=%u rc=%d text='%.100s'",
1141  client->server_name, header->qb.id, header->qb.size,
1142  client->msg_size,
1143  client->buffer + sizeof(pcmk__ipc_header_t));
1144 
1145  } else {
1146  crm_trace("No message received from %s IPC: %s",
1147  client->server_name, pcmk_strerror(client->msg_size));
1148 
1149  if (client->msg_size == -EAGAIN) {
1150  return -EAGAIN;
1151  }
1152  }
1153 
1154  if (!crm_ipc_connected(client) || client->msg_size == -ENOTCONN) {
1155  crm_err("Connection to %s IPC failed", client->server_name);
1156  }
1157 
1158  if (header) {
1159  /* Data excluding the header */
1160  return header->size_uncompressed;
1161  }
1162  return -ENOMSG;
1163 }
1164 
1165 const char *
1167 {
1168  pcmk__assert(client != NULL);
1169  return client->buffer + sizeof(pcmk__ipc_header_t);
1170 }
1171 
1172 uint32_t
1174 {
1175  pcmk__ipc_header_t *header = NULL;
1176 
1177  pcmk__assert(client != NULL);
1178  if (client->buffer == NULL) {
1179  return 0;
1180  }
1181 
1182  header = (pcmk__ipc_header_t *)(void*)client->buffer;
1183  return header->flags;
1184 }
1185 
1186 const char *
1188 {
1189  pcmk__assert(client != NULL);
1190  return client->server_name;
1191 }
1192 
1193 // \return Standard Pacemaker return code
1194 static int
1195 internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
1196  ssize_t *bytes)
1197 {
1198  time_t timeout = time(NULL) + 1 + pcmk__timeout_ms2s(ms_timeout);
1199  int rc = pcmk_rc_ok;
1200 
1201  /* get the reply */
1202  crm_trace("Waiting on reply to %s IPC message %d",
1203  client->server_name, request_id);
1204  do {
1205 
1206  *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1207  if (*bytes > 0) {
1208  pcmk__ipc_header_t *hdr = NULL;
1209 
1210  rc = crm_ipc_decompress(client);
1211  if (rc != pcmk_rc_ok) {
1212  return rc;
1213  }
1214 
1215  hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1216  if (hdr->qb.id == request_id) {
1217  /* Got it */
1218  break;
1219  } else if (hdr->qb.id < request_id) {
1220  xmlNode *bad = pcmk__xml_parse(crm_ipc_buffer(client));
1221 
1222  crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1223  crm_log_xml_notice(bad, "OldIpcReply");
1224 
1225  } else {
1226  xmlNode *bad = pcmk__xml_parse(crm_ipc_buffer(client));
1227 
1228  crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1229  crm_log_xml_notice(bad, "ImpossibleReply");
1230  pcmk__assert(hdr->qb.id <= request_id);
1231  }
1232  } else if (!crm_ipc_connected(client)) {
1233  crm_err("%s IPC provider disconnected while waiting for message %d",
1234  client->server_name, request_id);
1235  break;
1236  }
1237 
1238  } while (time(NULL) < timeout);
1239 
1240  if (*bytes < 0) {
1241  rc = (int) -*bytes; // System errno
1242  }
1243  return rc;
1244 }
1245 
1259 int
1260 crm_ipc_send(crm_ipc_t *client, const xmlNode *message,
1261  enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
1262 {
1263  int rc = 0;
1264  ssize_t qb_rc = 0;
1265  ssize_t bytes = 0;
1266  struct iovec *iov;
1267  static uint32_t id = 0;
1268  static int factor = 8;
1269  pcmk__ipc_header_t *header;
1270 
1271  if (client == NULL) {
1272  crm_notice("Can't send IPC request without connection (bug?): %.100s",
1273  message);
1274  return -ENOTCONN;
1275 
1276  } else if (!crm_ipc_connected(client)) {
1277  /* Don't even bother */
1278  crm_notice("Can't send %s IPC requests: Connection closed",
1279  client->server_name);
1280  return -ENOTCONN;
1281  }
1282 
1283  if (ms_timeout == 0) {
1284  ms_timeout = 5000;
1285  }
1286 
1287  if (client->need_reply) {
1288  qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1289  if (qb_rc < 0) {
1290  crm_warn("Sending %s IPC disabled until pending reply received",
1291  client->server_name);
1292  return -EALREADY;
1293 
1294  } else {
1295  crm_notice("Sending %s IPC re-enabled after pending reply received",
1296  client->server_name);
1297  client->need_reply = FALSE;
1298  }
1299  }
1300 
1301  id++;
1302  CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1303  rc = pcmk__ipc_prepare_iov(id, message, client->max_buf_size, &iov, &bytes);
1304  if (rc != pcmk_rc_ok) {
1305  crm_warn("Couldn't prepare %s IPC request: %s " QB_XS " rc=%d",
1306  client->server_name, pcmk_rc_str(rc), rc);
1307  return pcmk_rc2legacy(rc);
1308  }
1309 
1310  header = iov[0].iov_base;
1311  pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1312 
1314  /* Don't look for a synchronous response */
1316  }
1317 
1318  if(header->size_compressed) {
1319  if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
1320  crm_notice("Compressed message exceeds %d0%% of configured IPC "
1321  "limit (%u bytes); consider setting PCMK_ipc_buffer to "
1322  "%u or higher",
1323  factor, client->max_buf_size, 2 * client->max_buf_size);
1324  factor++;
1325  }
1326  }
1327 
1328  crm_trace("Sending %s IPC request %d of %u bytes using %dms timeout",
1329  client->server_name, header->qb.id, header->qb.size, ms_timeout);
1330 
1331  if ((ms_timeout > 0) || !pcmk_is_set(flags, crm_ipc_client_response)) {
1332 
1333  time_t timeout = time(NULL) + 1 + pcmk__timeout_ms2s(ms_timeout);
1334 
1335  do {
1336  /* @TODO Is this check really needed? Won't qb_ipcc_sendv() return
1337  * an error if it's not connected?
1338  */
1339  if (!crm_ipc_connected(client)) {
1340  goto send_cleanup;
1341  }
1342 
1343  qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1344  } while ((qb_rc == -EAGAIN) && (time(NULL) < timeout));
1345 
1346  rc = (int) qb_rc; // Negative of system errno, or bytes sent
1347  if (qb_rc <= 0) {
1348  goto send_cleanup;
1349 
1350  } else if (!pcmk_is_set(flags, crm_ipc_client_response)) {
1351  crm_trace("Not waiting for reply to %s IPC request %d",
1352  client->server_name, header->qb.id);
1353  goto send_cleanup;
1354  }
1355 
1356  rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes);
1357  if (rc != pcmk_rc_ok) {
1358  /* We didn't get the reply in time, so disable future sends for now.
1359  * The only alternative would be to close the connection since we
1360  * don't know how to detect and discard out-of-sequence replies.
1361  *
1362  * @TODO Implement out-of-sequence detection
1363  */
1364  client->need_reply = TRUE;
1365  }
1366  rc = (int) bytes; // Negative system errno, or size of reply received
1367 
1368  } else {
1369  // No timeout, and client response needed
1370  do {
1371  qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
1372  client->buf_size, -1);
1373  } while ((qb_rc == -EAGAIN) && crm_ipc_connected(client));
1374  rc = (int) qb_rc; // Negative system errno, or size of reply received
1375  }
1376 
1377  if (rc > 0) {
1378  pcmk__ipc_header_t *hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1379 
1380  crm_trace("Received %d-byte reply %d to %s IPC %d: %.100s",
1381  rc, hdr->qb.id, client->server_name, header->qb.id,
1382  crm_ipc_buffer(client));
1383 
1384  if (reply) {
1385  *reply = pcmk__xml_parse(crm_ipc_buffer(client));
1386  }
1387 
1388  } else {
1389  crm_trace("No reply to %s IPC %d: rc=%d",
1390  client->server_name, header->qb.id, rc);
1391  }
1392 
1393  send_cleanup:
1394  if (!crm_ipc_connected(client)) {
1395  crm_notice("Couldn't send %s IPC request %d: Connection closed "
1396  QB_XS " rc=%d", client->server_name, header->qb.id, rc);
1397 
1398  } else if (rc == -ETIMEDOUT) {
1399  crm_warn("%s IPC request %d failed: %s after %dms " QB_XS " rc=%d",
1400  client->server_name, header->qb.id, pcmk_strerror(rc),
1401  ms_timeout, rc);
1402  crm_write_blackbox(0, NULL);
1403 
1404  } else if (rc <= 0) {
1405  crm_warn("%s IPC request %d failed: %s " QB_XS " rc=%d",
1406  client->server_name, header->qb.id,
1407  ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1408  }
1409 
1410  pcmk_free_ipc_event(iov);
1411  return rc;
1412 }
1413 
1431 static int
1432 is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
1433  uid_t refuid, gid_t refgid,
1434  pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1435 {
1436  int rc = EOPNOTSUPP;
1437  pid_t found_pid = 0;
1438  uid_t found_uid = 0;
1439  gid_t found_gid = 0;
1440 
1441 #ifdef HAVE_QB_IPCC_AUTH_GET
1442  if (qb_ipc != NULL) {
1443  rc = qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid);
1444  rc = -rc; // libqb returns 0 or -errno
1445  if (rc == pcmk_rc_ok) {
1446  goto found;
1447  }
1448  }
1449 #endif
1450 
1451 #ifdef HAVE_UCRED
1452  {
1453  struct ucred ucred;
1454  socklen_t ucred_len = sizeof(ucred);
1455 
1456  if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) < 0) {
1457  rc = errno;
1458  } else if (ucred_len != sizeof(ucred)) {
1459  rc = EOPNOTSUPP;
1460  } else {
1461  found_pid = ucred.pid;
1462  found_uid = ucred.uid;
1463  found_gid = ucred.gid;
1464  goto found;
1465  }
1466  }
1467 #endif
1468 
1469 #ifdef HAVE_SOCKPEERCRED
1470  {
1471  struct sockpeercred sockpeercred;
1472  socklen_t sockpeercred_len = sizeof(sockpeercred);
1473 
1474  if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1475  &sockpeercred, &sockpeercred_len) < 0) {
1476  rc = errno;
1477  } else if (sockpeercred_len != sizeof(sockpeercred)) {
1478  rc = EOPNOTSUPP;
1479  } else {
1480  found_pid = sockpeercred.pid;
1481  found_uid = sockpeercred.uid;
1482  found_gid = sockpeercred.gid;
1483  goto found;
1484  }
1485  }
1486 #endif
1487 
1488 #ifdef HAVE_GETPEEREID // For example, FreeBSD
1489  if (getpeereid(sock, &found_uid, &found_gid) < 0) {
1490  rc = errno;
1491  } else {
1492  found_pid = PCMK__SPECIAL_PID;
1493  goto found;
1494  }
1495 #endif
1496 
1497 #ifdef HAVE_GETPEERUCRED
1498  {
1499  ucred_t *ucred = NULL;
1500 
1501  if (getpeerucred(sock, &ucred) < 0) {
1502  rc = errno;
1503  } else {
1504  found_pid = ucred_getpid(ucred);
1505  found_uid = ucred_geteuid(ucred);
1506  found_gid = ucred_getegid(ucred);
1507  ucred_free(ucred);
1508  goto found;
1509  }
1510  }
1511 #endif
1512 
1513  return rc; // If we get here, nothing succeeded
1514 
1515 found:
1516  if (gotpid != NULL) {
1517  *gotpid = found_pid;
1518  }
1519  if (gotuid != NULL) {
1520  *gotuid = found_uid;
1521  }
1522  if (gotgid != NULL) {
1523  *gotgid = found_gid;
1524  }
1525  if ((found_uid != 0) && (found_uid != refuid) && (found_gid != refgid)) {
1526  return pcmk_rc_ipc_unauthorized;
1527  }
1528  return pcmk_rc_ok;
1529 }
1530 
1531 int
1532 crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
1533  pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1534 {
1535  int ret = is_ipc_provider_expected(NULL, sock, refuid, refgid,
1536  gotpid, gotuid, gotgid);
1537 
1538  /* The old function had some very odd return codes*/
1539  if (ret == 0) {
1540  return 1;
1541  } else if (ret == pcmk_rc_ipc_unauthorized) {
1542  return 0;
1543  } else {
1544  return pcmk_rc2legacy(ret);
1545  }
1546 }
1547 
1548 int
1550  gid_t refgid, pid_t *gotpid)
1551 {
1552  static char last_asked_name[PATH_MAX / 2] = ""; /* log spam prevention */
1553  int fd;
1554  int rc = pcmk_rc_ipc_unresponsive;
1555  int auth_rc = 0;
1556  int32_t qb_rc;
1557  pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1558  qb_ipcc_connection_t *c;
1559 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1560  struct pollfd pollfd = { 0, };
1561  int poll_rc;
1562 
1563  c = qb_ipcc_connect_async(name, 0,
1564  &(pollfd.fd));
1565 #else
1566  c = qb_ipcc_connect(name, 0);
1567 #endif
1568  if (c == NULL) {
1569  crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1571  goto bail;
1572  }
1573 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1574  pollfd.events = POLLIN;
1575  do {
1576  poll_rc = poll(&pollfd, 1, 2000);
1577  } while ((poll_rc == -1) && (errno == EINTR));
1578 
1579  /* If poll() failed, given that disconnect function is not registered yet,
1580  * qb_ipcc_disconnect() won't clean up the socket. In any case, call
1581  * qb_ipcc_connect_continue() here so that it may fail and do the cleanup
1582  * for us.
1583  */
1584  if (qb_ipcc_connect_continue(c) != 0) {
1585  crm_info("Could not connect to %s IPC: %s", name,
1586  (poll_rc == 0)?"timeout":strerror(errno));
1588  c = NULL; // qb_ipcc_connect_continue cleaned up for us
1589  goto bail;
1590  }
1591 #endif
1592 
1593  qb_rc = qb_ipcc_fd_get(c, &fd);
1594  if (qb_rc != 0) {
1595  rc = (int) -qb_rc; // System errno
1596  crm_err("Could not get fd from %s IPC: %s " QB_XS " rc=%d",
1597  name, pcmk_rc_str(rc), rc);
1598  goto bail;
1599  }
1600 
1601  auth_rc = is_ipc_provider_expected(c, fd, refuid, refgid,
1602  &found_pid, &found_uid, &found_gid);
1603  if (auth_rc == pcmk_rc_ipc_unauthorized) {
1604  crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1605  " process %lld (uid: %lld, gid: %lld)",
1606  name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1607  (long long) found_uid, (long long) found_gid);
1609  goto bail;
1610  }
1611 
1612  if (auth_rc != pcmk_rc_ok) {
1613  rc = auth_rc;
1614  crm_err("Could not get peer credentials from %s IPC: %s "
1615  QB_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1616  goto bail;
1617  }
1618 
1619  if (gotpid != NULL) {
1620  *gotpid = found_pid;
1621  }
1622 
1623  rc = pcmk_rc_ok;
1624  if ((found_uid != refuid || found_gid != refgid)
1625  && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1626  if ((found_uid == 0) && (refuid != 0)) {
1627  crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1628  " credentials are %lld:%lld, hazard of violating"
1629  " the least privilege principle",
1630  name, (long long) refuid, (long long) refgid);
1631  } else {
1632  crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1633  " expected credentials are %lld:%lld, which may"
1634  " mean a different set of privileges than expected",
1635  name, (long long) found_uid, (long long) found_gid,
1636  (long long) refuid, (long long) refgid);
1637  }
1638  memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1639  }
1640 
1641 bail:
1642  if (c != NULL) {
1643  qb_ipcc_disconnect(c);
1644  }
1645  return rc;
1646 }
1647 
1648 // Deprecated functions kept only for backward API compatibility
1649 // LCOV_EXCL_START
1650 
1652 
1653 bool
1655 {
1656  int rc = pcmk__connect_generic_ipc(client);
1657 
1658  if (rc == pcmk_rc_ok) {
1659  return true;
1660  }
1661  if ((client != NULL) && (client->ipc == NULL)) {
1662  errno = (rc > 0)? rc : ENOTCONN;
1663  crm_debug("Could not establish %s IPC connection: %s (%d)",
1664  client->server_name, pcmk_rc_str(errno), errno);
1665  } else if (rc == pcmk_rc_ipc_unauthorized) {
1666  crm_err("%s IPC provider authentication failed",
1667  (client == NULL)? "Pacemaker" : client->server_name);
1668  errno = ECONNABORTED;
1669  } else {
1670  crm_err("Could not verify authenticity of %s IPC provider",
1671  (client == NULL)? "Pacemaker" : client->server_name);
1672  errno = ENOTCONN;
1673  }
1674  return false;
1675 }
1676 
1677 // LCOV_EXCL_STOP
1678 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
A dumping ground.
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
Definition: ipc_client.c:1001
#define crm_notice(fmt, args...)
Definition: logging.h:365
const char * pcmk_strerror(int rc)
Definition: results.c:257
const char * pcmk__server_log_name(enum pcmk_ipc_server server)
Definition: servers.c:126
enum pcmk_ipc_dispatch dispatch_type
Scheduler.
Definition: ipc.h:56
#define PCMK__ATTRD_CMD_PEER_REMOVE
Definition: crm_internal.h:80
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition: ipc_client.c:658
int pcmk_rc2legacy(int rc)
Definition: results.c:654
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
Definition: xml_element.c:1480
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1118
#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:55
Deprecated Pacemaker IPC APIs.
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:1166
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:791
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:41
#define PCMK__SPECIAL_PID_AS_0(p)
Definition: ipc_internal.h:53
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:46
#define PCMK__SPECIAL_PID
Definition: ipc_internal.h:41
char * crm_system_name
Definition: utils.c:44
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:592
enum crm_exit_e crm_exit_t
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:966
const char * pcmk__server_ipc_name(enum pcmk_ipc_server server)
Definition: servers.c:144
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:389
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:196
int pcmk_daemon_user(uid_t *uid, gid_t *gid)
Get user and group IDs of pacemaker daemon user.
Definition: utils.c:139
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:609
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:1014
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid)
Definition: ipc_client.c:1549
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: xml_element.c:1120
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
struct qb_ipc_response_header qb
CIB manager.
Definition: ipc.h:51
Caller will poll and dispatch IPC.
Definition: ipc.h:76
#define crm_warn(fmt, args...)
Definition: logging.h:362
pcmk_ipc_server
Available IPC interfaces.
Definition: ipc.h:48
void pcmk__sleep_ms(unsigned int ms)
Definition: utils.c:355
#define crm_debug(fmt, args...)
Definition: logging.h:370
bool crm_ipc_connect(crm_ipc_t *client)
Definition: ipc_client.c:1654
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:844
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:151
#define PCMK_XA_UNAME
Definition: xml_names.h:431
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:635
pcmk_ipc_callback_t cb
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__attrd_api_methods(void)
Definition: ipc_attrd.c:114
#define crm_trace(fmt, args...)
Definition: logging.h:372
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
#define PCMK_XA_TASK
Definition: xml_names.h:424
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:1173
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
Definition: ipc_internal.h:205
Wrappers for and extensions to libxml2.
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance.
Definition: ipc_client.c:584
G_GNUC_INTERNAL bool pcmk__valid_ipc_header(const pcmk__ipc_header_t *header)
Definition: ipc_common.c:107
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:953
#define pcmk__new_request(server, sender_system, recipient_node, recipient_system, task, data)
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:941
#define PCMK_XA_ID
Definition: xml_names.h:301
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:667
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:98
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:861
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:168
void crm_write_blackbox(int nsig, const struct qb_log_callsite *callsite)
Definition: logging.c:519
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:890
#define pcmk__assert(expr)
#define CRM_OP_RM_NODE_CACHE
Definition: crm.h:131
pcmk_ipc_dispatch
How IPC replies should be dispatched.
Definition: ipc.h:74
int pcmk__bzlib2rc(int bz2)
Map a bz2 return code to the most similar Pacemaker return code.
Definition: results.c:1014
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
Definition: ipc.h:61
#define ENODATA
Definition: portability.h:61
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:1028
Attach IPC to GMainLoop for dispatch.
Definition: ipc.h:75
Termination of IPC connection.
Definition: ipc.h:65
mainloop_io_t * mainloop_io
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
Executor.
Definition: ipc.h:53
Controller.
Definition: ipc.h:52
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:198
#define crm_err(fmt, args...)
Definition: logging.h:359
Sending a command will wait for any reply.
Definition: ipc.h:77
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop)
Definition: ipc_client.c:429
#define crm_log_xml_notice(xml, text)
Definition: logging.h:377
Lost connection to something.
Definition: results.h:264
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1060
guint pcmk__timeout_ms2s(guint timeout_ms)
Definition: utils.c:425
void(* free_data)(void *api_data)
Fencer.
Definition: ipc.h:54
#define pcmk__plural_s(i)
#define pcmk_ok
Definition: results.h:65
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active.
Definition: ipc_client.c:277
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:491
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:561
#define crm_log_xml_trace(xml, text)
Definition: logging.h:380
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__controld_api_methods(void)
Definition: ipc_controld.c:299
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:1260
#define PCMK__XA_T
void pcmk__xe_add_node(xmlNode *xml, const char *node, int nodeid)
Definition: nodes.c:147
void(* post_disconnect)(pcmk_ipc_api_t *api)
#define PCMK__XA_REAP
Attribute manager.
Definition: ipc.h:50
enum pcmk_ipc_server server
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
crm_ipc_flags
Definition: ipc.h:135
unsigned int timeout
Definition: pcmk_fence.c:34
#define crm_info(fmt, args...)
Definition: logging.h:367
#define PCMK__XA_SRC
uint64_t flags
Definition: remote.c:211
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:96
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:1532
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc_client.c:1187