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