pacemaker  2.0.1-9e909a5bdd
Scalable High-Availability cluster resource manager
ipc.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #include <sys/param.h>
11 
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <grp.h>
17 
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <bzlib.h>
21 
22 #include <crm/crm.h>
23 #include <crm/msg_xml.h>
24 #include <crm/common/ipc.h>
25 #include <crm/common/ipcs.h>
26 
27 #define PCMK_IPC_VERSION 1
28 
29 /* Evict clients whose event queue grows this large (by default) */
30 #define PCMK_IPC_DEFAULT_QUEUE_MAX 500
31 
32 struct crm_ipc_response_header {
33  struct qb_ipc_response_header qb;
34  uint32_t size_uncompressed;
35  uint32_t size_compressed;
37  uint8_t version; /* Protect against version changes for anyone that might bother to statically link us */
38 };
39 
40 static int hdr_offset = 0;
41 static unsigned int ipc_buffer_max = 0;
42 static unsigned int pick_ipc_buffer(unsigned int max);
43 
44 static inline void
45 crm_ipc_init(void)
46 {
47  if (hdr_offset == 0) {
48  hdr_offset = sizeof(struct crm_ipc_response_header);
49  }
50  if (ipc_buffer_max == 0) {
51  ipc_buffer_max = pick_ipc_buffer(0);
52  }
53 }
54 
55 unsigned int
57 {
58  return pick_ipc_buffer(0);
59 }
60 
61 static char *
62 generateReference(const char *custom1, const char *custom2)
63 {
64  static uint ref_counter = 0;
65 
66  return crm_strdup_printf("%s-%s-%lu-%u",
67  (custom1? custom1 : "_empty_"),
68  (custom2? custom2 : "_empty_"),
69  (unsigned long)time(NULL), ref_counter++);
70 }
71 
72 xmlNode *
73 create_request_adv(const char *task, xmlNode * msg_data,
74  const char *host_to, const char *sys_to,
75  const char *sys_from, const char *uuid_from, const char *origin)
76 {
77  char *true_from = NULL;
78  xmlNode *request = NULL;
79  char *reference = generateReference(task, sys_from);
80 
81  if (uuid_from != NULL) {
82  true_from = generate_hash_key(sys_from, uuid_from);
83  } else if (sys_from != NULL) {
84  true_from = strdup(sys_from);
85  } else {
86  crm_err("No sys from specified");
87  }
88 
89  // host_from will get set for us if necessary by the controller when routed
90  request = create_xml_node(NULL, __FUNCTION__);
91  crm_xml_add(request, F_CRM_ORIGIN, origin);
92  crm_xml_add(request, F_TYPE, T_CRM);
95  crm_xml_add(request, F_CRM_REFERENCE, reference);
96  crm_xml_add(request, F_CRM_TASK, task);
97  crm_xml_add(request, F_CRM_SYS_TO, sys_to);
98  crm_xml_add(request, F_CRM_SYS_FROM, true_from);
99 
100  /* HOSTTO will be ignored if it is to the DC anyway. */
101  if (host_to != NULL && strlen(host_to) > 0) {
102  crm_xml_add(request, F_CRM_HOST_TO, host_to);
103  }
104 
105  if (msg_data != NULL) {
106  add_message_xml(request, F_CRM_DATA, msg_data);
107  }
108  free(reference);
109  free(true_from);
110 
111  return request;
112 }
113 
114 /*
115  * This method adds a copy of xml_response_data
116  */
117 xmlNode *
118 create_reply_adv(xmlNode * original_request, xmlNode * xml_response_data, const char *origin)
119 {
120  xmlNode *reply = NULL;
121 
122  const char *host_from = crm_element_value(original_request, F_CRM_HOST_FROM);
123  const char *sys_from = crm_element_value(original_request, F_CRM_SYS_FROM);
124  const char *sys_to = crm_element_value(original_request, F_CRM_SYS_TO);
125  const char *type = crm_element_value(original_request, F_CRM_MSG_TYPE);
126  const char *operation = crm_element_value(original_request, F_CRM_TASK);
127  const char *crm_msg_reference = crm_element_value(original_request, F_CRM_REFERENCE);
128 
129  if (type == NULL) {
130  crm_err("Cannot create new_message, no message type in original message");
131  CRM_ASSERT(type != NULL);
132  return NULL;
133 #if 0
134  } else if (strcasecmp(XML_ATTR_REQUEST, type) != 0) {
135  crm_err("Cannot create new_message, original message was not a request");
136  return NULL;
137 #endif
138  }
139  reply = create_xml_node(NULL, __FUNCTION__);
140  if (reply == NULL) {
141  crm_err("Cannot create new_message, malloc failed");
142  return NULL;
143  }
144 
145  crm_xml_add(reply, F_CRM_ORIGIN, origin);
146  crm_xml_add(reply, F_TYPE, T_CRM);
149  crm_xml_add(reply, F_CRM_REFERENCE, crm_msg_reference);
150  crm_xml_add(reply, F_CRM_TASK, operation);
151 
152  /* since this is a reply, we reverse the from and to */
153  crm_xml_add(reply, F_CRM_SYS_TO, sys_from);
154  crm_xml_add(reply, F_CRM_SYS_FROM, sys_to);
155 
156  /* HOSTTO will be ignored if it is to the DC anyway. */
157  if (host_from != NULL && strlen(host_from) > 0) {
158  crm_xml_add(reply, F_CRM_HOST_TO, host_from);
159  }
160 
161  if (xml_response_data != NULL) {
162  add_message_xml(reply, F_CRM_DATA, xml_response_data);
163  }
164 
165  return reply;
166 }
167 
168 /* Libqb based IPC */
169 
170 /* Server... */
171 
172 GHashTable *client_connections = NULL;
173 
174 crm_client_t *
175 crm_client_get(qb_ipcs_connection_t * c)
176 {
177  if (client_connections) {
178  return g_hash_table_lookup(client_connections, c);
179  }
180 
181  crm_trace("No client found for %p", c);
182  return NULL;
183 }
184 
185 crm_client_t *
186 crm_client_get_by_id(const char *id)
187 {
188  gpointer key;
189  crm_client_t *client;
190  GHashTableIter iter;
191 
192  if (client_connections && id) {
193  g_hash_table_iter_init(&iter, client_connections);
194  while (g_hash_table_iter_next(&iter, &key, (gpointer *) & client)) {
195  if (strcmp(client->id, id) == 0) {
196  return client;
197  }
198  }
199  }
200 
201  crm_trace("No client found with id=%s", id);
202  return NULL;
203 }
204 
205 const char *
207 {
208  if (c == NULL) {
209  return "null";
210  } else if (c->name == NULL && c->id == NULL) {
211  return "unknown";
212  } else if (c->name == NULL) {
213  return c->id;
214  } else {
215  return c->name;
216  }
217 }
218 
219 const char *
221 {
222  switch (client_type) {
223  case CRM_CLIENT_IPC:
224  return "IPC";
225  case CRM_CLIENT_TCP:
226  return "TCP";
227 #ifdef HAVE_GNUTLS_GNUTLS_H
228  case CRM_CLIENT_TLS:
229  return "TLS";
230 #endif
231  default:
232  return "unknown";
233  }
234 }
235 
236 void
238 {
239  if (client_connections == NULL) {
240  crm_trace("Creating client hash table");
241  client_connections = g_hash_table_new(g_direct_hash, g_direct_equal);
242  }
243 }
244 
245 void
247 {
248  if (client_connections != NULL) {
249  int active = g_hash_table_size(client_connections);
250 
251  if (active) {
252  crm_err("Exiting with %d active connections", active);
253  }
254  g_hash_table_destroy(client_connections); client_connections = NULL;
255  }
256 }
257 
258 void
259 crm_client_disconnect_all(qb_ipcs_service_t *service)
260 {
261  qb_ipcs_connection_t *c = NULL;
262 
263  if (service == NULL) {
264  return;
265  }
266 
267  c = qb_ipcs_connection_first_get(service);
268 
269  while (c != NULL) {
270  qb_ipcs_connection_t *last = c;
271 
272  c = qb_ipcs_connection_next_get(service, last);
273 
274  /* There really shouldn't be anyone connected at this point */
275  crm_notice("Disconnecting client %p, pid=%d...", last, crm_ipcs_client_pid(last));
276  qb_ipcs_disconnect(last);
277  qb_ipcs_connection_unref(last);
278  }
279 }
280 
291 static crm_client_t *
292 client_from_connection(qb_ipcs_connection_t *c, void *key, uid_t uid_client)
293 {
294  crm_client_t *client = calloc(1, sizeof(crm_client_t));
295 
296  if (client == NULL) {
297  crm_perror(LOG_ERR, "Allocating client");
298  return NULL;
299  }
300 
301  if (c) {
302 #if ENABLE_ACL
303  client->user = uid2username(uid_client);
304  if (client->user == NULL) {
305  client->user = strdup("#unprivileged");
306  CRM_CHECK(client->user != NULL, free(client); return NULL);
307  crm_err("Unable to enforce ACLs for user ID %d, assuming unprivileged",
308  uid_client);
309  }
310 #endif
311  client->ipcs = c;
312  client->kind = CRM_CLIENT_IPC;
313  client->pid = crm_ipcs_client_pid(c);
314  if (key == NULL) {
315  key = c;
316  }
317  }
318 
319  client->id = crm_generate_uuid();
320  if (client->id == NULL) {
321  crm_err("Could not generate UUID for client");
322  free(client->user);
323  free(client);
324  return NULL;
325  }
326  if (key == NULL) {
327  key = client->id;
328  }
329  g_hash_table_insert(client_connections, key, client);
330  return client;
331 }
332 
340 crm_client_t *
342 {
343  crm_client_t *client = client_from_connection(NULL, key, 0);
344 
345  CRM_ASSERT(client != NULL);
346  return client;
347 }
348 
349 crm_client_t *
350 crm_client_new(qb_ipcs_connection_t * c, uid_t uid_client, gid_t gid_client)
351 {
352  static gid_t uid_cluster = 0;
353  static gid_t gid_cluster = 0;
354 
355  crm_client_t *client = NULL;
356 
357  CRM_CHECK(c != NULL, return NULL);
358 
359  if (uid_cluster == 0) {
360  if (crm_user_lookup(CRM_DAEMON_USER, &uid_cluster, &gid_cluster) < 0) {
361  static bool need_log = TRUE;
362 
363  if (need_log) {
364  crm_warn("Could not find user and group IDs for user %s",
366  need_log = FALSE;
367  }
368  }
369  }
370 
371  if (uid_client != 0) {
372  crm_trace("Giving access to group %u", gid_cluster);
373  /* Passing -1 to chown(2) means don't change */
374  qb_ipcs_connection_auth_set(c, -1, gid_cluster, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
375  }
376 
377  crm_client_init();
378 
379  /* TODO: Do our own auth checking, return NULL if unauthorized */
380  client = client_from_connection(c, NULL, uid_client);
381  if (client == NULL) {
382  return NULL;
383  }
384 
385  if ((uid_client == 0) || (uid_client == uid_cluster)) {
386  /* Remember when a connection came from root or hacluster */
388  }
389 
390  crm_debug("Connecting %p for uid=%d gid=%d pid=%u id=%s", c, uid_client, gid_client, client->pid, client->id);
391 
392  return client;
393 }
394 
395 static struct iovec *
396 pcmk__new_ipc_event()
397 {
398  struct iovec *iov = calloc(2, sizeof(struct iovec));
399 
400  CRM_ASSERT(iov != NULL);
401  return iov;
402 }
403 
409 void
410 pcmk_free_ipc_event(struct iovec *event)
411 {
412  if (event != NULL) {
413  free(event[0].iov_base);
414  free(event[1].iov_base);
415  free(event);
416  }
417 }
418 
419 static void
420 free_event(gpointer data)
421 {
422  pcmk_free_ipc_event((struct iovec *) data);
423 }
424 
425 static void
426 add_event(crm_client_t *c, struct iovec *iov)
427 {
428  if (c->event_queue == NULL) {
429  c->event_queue = g_queue_new();
430  }
431  g_queue_push_tail(c->event_queue, iov);
432 }
433 
434 void
436 {
437  if (c == NULL) {
438  return;
439  }
440 
441  if (client_connections) {
442  if (c->ipcs) {
443  crm_trace("Destroying %p/%p (%d remaining)",
444  c, c->ipcs, crm_hash_table_size(client_connections) - 1);
445  g_hash_table_remove(client_connections, c->ipcs);
446 
447  } else {
448  crm_trace("Destroying remote connection %p (%d remaining)",
449  c, crm_hash_table_size(client_connections) - 1);
450  g_hash_table_remove(client_connections, c->id);
451  }
452  }
453 
454  if (c->event_timer) {
455  g_source_remove(c->event_timer);
456  }
457 
458  if (c->event_queue) {
459  crm_debug("Destroying %d events", g_queue_get_length(c->event_queue));
460  g_queue_free_full(c->event_queue, free_event);
461  }
462 
463  free(c->id);
464  free(c->name);
465  free(c->user);
466  if (c->remote) {
467  if (c->remote->auth_timeout) {
468  g_source_remove(c->remote->auth_timeout);
469  }
470  free(c->remote->buffer);
471  free(c->remote);
472  }
473  free(c);
474 }
475 
484 bool
485 crm_set_client_queue_max(crm_client_t *client, const char *qmax)
486 {
487  if (is_set(client->flags, crm_client_flag_ipc_privileged)) {
488  int qmax_int = crm_int_helper(qmax, NULL);
489 
490  if ((errno == 0) && (qmax_int > 0)) {
491  client->queue_max = qmax_int;
492  return TRUE;
493  }
494  }
495  return FALSE;
496 }
497 
498 int
499 crm_ipcs_client_pid(qb_ipcs_connection_t * c)
500 {
501  struct qb_ipcs_connection_stats stats;
502 
503  stats.client_pid = 0;
504  qb_ipcs_connection_stats_get(c, &stats, 0);
505  return stats.client_pid;
506 }
507 
508 xmlNode *
510 {
511  xmlNode *xml = NULL;
512  char *uncompressed = NULL;
513  char *text = ((char *)data) + sizeof(struct crm_ipc_response_header);
514  struct crm_ipc_response_header *header = data;
515 
516  if (id) {
517  *id = ((struct qb_ipc_response_header *)data)->id;
518  }
519  if (flags) {
520  *flags = header->flags;
521  }
522 
523  if (is_set(header->flags, crm_ipc_proxied)) {
524  /* Mark this client as being the endpoint of a proxy connection.
525  * Proxy connections responses are sent on the event channel, to avoid
526  * blocking the controller serving as proxy.
527  */
529  }
530 
531  if(header->version > PCMK_IPC_VERSION) {
532  crm_err("Filtering incompatible v%d IPC message, we only support versions <= %d",
533  header->version, PCMK_IPC_VERSION);
534  return NULL;
535  }
536 
537  if (header->size_compressed) {
538  int rc = 0;
539  unsigned int size_u = 1 + header->size_uncompressed;
540  uncompressed = calloc(1, size_u);
541 
542  crm_trace("Decompressing message data %u bytes into %u bytes",
543  header->size_compressed, size_u);
544 
545  rc = BZ2_bzBuffToBuffDecompress(uncompressed, &size_u, text, header->size_compressed, 1, 0);
546  text = uncompressed;
547 
548  if (rc != BZ_OK) {
549  crm_err("Decompression failed: %s " CRM_XS " bzerror=%d",
550  bz2_strerror(rc), rc);
551  free(uncompressed);
552  return NULL;
553  }
554  }
555 
556  CRM_ASSERT(text[header->size_uncompressed - 1] == 0);
557 
558  crm_trace("Received %.200s", text);
559  xml = string2xml(text);
560 
561  free(uncompressed);
562  return xml;
563 }
564 
566 
567 static gboolean
568 crm_ipcs_flush_events_cb(gpointer data)
569 {
570  crm_client_t *c = data;
571 
572  c->event_timer = 0;
574  return FALSE;
575 }
576 
584 static inline void
585 delay_next_flush(crm_client_t *c, unsigned int queue_len)
586 {
587  /* Delay a maximum of 1.5 seconds */
588  guint delay = (queue_len < 5)? (1000 + 100 * queue_len) : 1500;
589 
590  c->event_timer = g_timeout_add(delay, crm_ipcs_flush_events_cb, c);
591 }
592 
593 ssize_t
595 {
596  ssize_t rc = 0;
597  unsigned int sent = 0;
598  unsigned int queue_len = 0;
599 
600  if (c == NULL) {
601  return pcmk_ok;
602 
603  } else if (c->event_timer) {
604  /* There is already a timer, wait until it goes off */
605  crm_trace("Timer active for %p - %d", c->ipcs, c->event_timer);
606  return pcmk_ok;
607  }
608 
609  if (c->event_queue) {
610  queue_len = g_queue_get_length(c->event_queue);
611  }
612  while (sent < 100) {
613  struct crm_ipc_response_header *header = NULL;
614  struct iovec *event = NULL;
615 
616  if (c->event_queue) {
617  // We don't pop unless send is successful
618  event = g_queue_peek_head(c->event_queue);
619  }
620  if (event == NULL) { // Queue is empty
621  break;
622  }
623 
624  rc = qb_ipcs_event_sendv(c->ipcs, event, 2);
625  if (rc < 0) {
626  break;
627  }
628  event = g_queue_pop_head(c->event_queue);
629 
630  sent++;
631  header = event[0].iov_base;
632  if (header->size_compressed) {
633  crm_trace("Event %d to %p[%d] (%lld compressed bytes) sent",
634  header->qb.id, c->ipcs, c->pid, (long long) rc);
635  } else {
636  crm_trace("Event %d to %p[%d] (%lld bytes) sent: %.120s",
637  header->qb.id, c->ipcs, c->pid, (long long) rc,
638  (char *) (event[1].iov_base));
639  }
640  pcmk_free_ipc_event(event);
641  }
642 
643  queue_len -= sent;
644  if (sent > 0 || queue_len) {
645  crm_trace("Sent %d events (%d remaining) for %p[%d]: %s (%lld)",
646  sent, queue_len, c->ipcs, c->pid,
647  pcmk_strerror(rc < 0 ? rc : 0), (long long) rc);
648  }
649 
650  if (queue_len) {
651 
652  /* Allow clients to briefly fall behind on processing incoming messages,
653  * but drop completely unresponsive clients so the connection doesn't
654  * consume resources indefinitely.
655  */
656  if (queue_len > QB_MAX(c->queue_max, PCMK_IPC_DEFAULT_QUEUE_MAX)) {
657  if ((c->queue_backlog <= 1) || (queue_len < c->queue_backlog)) {
658  /* Don't evict for a new or shrinking backlog */
659  crm_warn("Client with process ID %u has a backlog of %u messages "
660  CRM_XS " %p", c->pid, queue_len, c->ipcs);
661  } else {
662  crm_err("Evicting client with process ID %u due to backlog of %u messages "
663  CRM_XS " %p", c->pid, queue_len, c->ipcs);
664  c->queue_backlog = 0;
665  qb_ipcs_disconnect(c->ipcs);
666  return rc;
667  }
668  }
669 
670  c->queue_backlog = queue_len;
671  delay_next_flush(c, queue_len);
672 
673  } else {
674  /* Event queue is empty, there is no backlog */
675  c->queue_backlog = 0;
676  }
677 
678  return rc;
679 }
680 
681 ssize_t
682 crm_ipc_prepare(uint32_t request, xmlNode * message, struct iovec ** result, uint32_t max_send_size)
683 {
684  static unsigned int biggest = 0;
685  struct iovec *iov;
686  unsigned int total = 0;
687  char *compressed = NULL;
688  char *buffer = dump_xml_unformatted(message);
689  struct crm_ipc_response_header *header = calloc(1, sizeof(struct crm_ipc_response_header));
690 
691  CRM_ASSERT(result != NULL);
692 
693  crm_ipc_init();
694 
695  if (max_send_size == 0) {
696  max_send_size = ipc_buffer_max;
697  }
698 
699  CRM_LOG_ASSERT(max_send_size != 0);
700 
701  *result = NULL;
702  iov = pcmk__new_ipc_event();
703  iov[0].iov_len = hdr_offset;
704  iov[0].iov_base = header;
705 
706  header->version = PCMK_IPC_VERSION;
707  header->size_uncompressed = 1 + strlen(buffer);
708  total = iov[0].iov_len + header->size_uncompressed;
709 
710  if (total < max_send_size) {
711  iov[1].iov_base = buffer;
712  iov[1].iov_len = header->size_uncompressed;
713 
714  } else {
715  unsigned int new_size = 0;
716 
718  (buffer, header->size_uncompressed, max_send_size, &compressed, &new_size)) {
719 
720  header->flags |= crm_ipc_compressed;
721  header->size_compressed = new_size;
722 
723  iov[1].iov_len = header->size_compressed;
724  iov[1].iov_base = compressed;
725 
726  free(buffer);
727 
728  biggest = QB_MAX(header->size_compressed, biggest);
729 
730  } else {
731  ssize_t rc = -EMSGSIZE;
732 
733  crm_log_xml_trace(message, "EMSGSIZE");
734  biggest = QB_MAX(header->size_uncompressed, biggest);
735 
736  crm_err
737  ("Could not compress the message (%u bytes) into less than the configured ipc limit (%u bytes). "
738  "Set PCMK_ipc_buffer to a higher value (%u bytes suggested)",
739  header->size_uncompressed, max_send_size, 4 * biggest);
740 
741  free(compressed);
742  pcmk_free_ipc_event(iov);
743  return rc;
744  }
745  }
746 
747  header->qb.size = iov[0].iov_len + iov[1].iov_len;
748  header->qb.id = (int32_t)request; /* Replying to a specific request */
749 
750  *result = iov;
751  CRM_ASSERT(header->qb.size > 0);
752  return header->qb.size;
753 }
754 
755 ssize_t
756 crm_ipcs_sendv(crm_client_t * c, struct iovec * iov, enum crm_ipc_flags flags)
757 {
758  ssize_t rc;
759  static uint32_t id = 1;
760  struct crm_ipc_response_header *header = iov[0].iov_base;
761 
763  /* _ALL_ replies to proxied connections need to be sent as events */
764  if (is_not_set(flags, crm_ipc_server_event)) {
765  flags |= crm_ipc_server_event;
766  /* this flag lets us know this was originally meant to be a response.
767  * even though we're sending it over the event channel. */
769  }
770  }
771 
772  header->flags |= flags;
773  if (flags & crm_ipc_server_event) {
774  header->qb.id = id++; /* We don't really use it, but doesn't hurt to set one */
775 
776  if (flags & crm_ipc_server_free) {
777  crm_trace("Sending the original to %p[%d]", c->ipcs, c->pid);
778  add_event(c, iov);
779 
780  } else {
781  struct iovec *iov_copy = pcmk__new_ipc_event();
782 
783  crm_trace("Sending a copy to %p[%d]", c->ipcs, c->pid);
784  iov_copy[0].iov_len = iov[0].iov_len;
785  iov_copy[0].iov_base = malloc(iov[0].iov_len);
786  memcpy(iov_copy[0].iov_base, iov[0].iov_base, iov[0].iov_len);
787 
788  iov_copy[1].iov_len = iov[1].iov_len;
789  iov_copy[1].iov_base = malloc(iov[1].iov_len);
790  memcpy(iov_copy[1].iov_base, iov[1].iov_base, iov[1].iov_len);
791 
792  add_event(c, iov_copy);
793  }
794 
795  } else {
796  CRM_LOG_ASSERT(header->qb.id != 0); /* Replying to a specific request */
797 
798  rc = qb_ipcs_response_sendv(c->ipcs, iov, 2);
799  if (rc < header->qb.size) {
800  crm_notice("Response %d to pid %d failed: %s "
801  CRM_XS " bytes=%u rc=%lld ipcs=%p",
802  header->qb.id, c->pid, pcmk_strerror(rc),
803  header->qb.size, (long long) rc, c->ipcs);
804 
805  } else {
806  crm_trace("Response %d sent, %lld bytes to %p[%d]",
807  header->qb.id, (long long) rc, c->ipcs, c->pid);
808  }
809 
810  if (flags & crm_ipc_server_free) {
811  pcmk_free_ipc_event(iov);
812  }
813  }
814 
815  if (flags & crm_ipc_server_event) {
816  rc = crm_ipcs_flush_events(c);
817  } else {
819  }
820 
821  if (rc == -EPIPE || rc == -ENOTCONN) {
822  crm_trace("Client %p disconnected", c->ipcs);
823  }
824 
825  return rc;
826 }
827 
828 ssize_t
829 crm_ipcs_send(crm_client_t * c, uint32_t request, xmlNode * message,
830  enum crm_ipc_flags flags)
831 {
832  struct iovec *iov = NULL;
833  ssize_t rc = 0;
834 
835  if(c == NULL) {
836  return -EDESTADDRREQ;
837  }
838  crm_ipc_init();
839 
840  rc = crm_ipc_prepare(request, message, &iov, ipc_buffer_max);
841  if (rc > 0) {
842  rc = crm_ipcs_sendv(c, iov, flags | crm_ipc_server_free);
843  } else {
844  pcmk_free_ipc_event(iov);
845  crm_notice("Message to pid %d failed: %s " CRM_XS " rc=%lld ipcs=%p",
846  c->pid, pcmk_strerror(rc), (long long) rc, c->ipcs);
847  }
848  return rc;
849 }
850 
851 void
852 crm_ipcs_send_ack(crm_client_t * c, uint32_t request, uint32_t flags, const char *tag, const char *function,
853  int line)
854 {
855  if (flags & crm_ipc_client_response) {
856  xmlNode *ack = create_xml_node(NULL, tag);
857 
858  crm_trace("Ack'ing msg from %s (%p)", crm_client_name(c), c);
859  c->request_id = 0;
860  crm_xml_add(ack, "function", function);
861  crm_xml_add_int(ack, "line", line);
862  crm_ipcs_send(c, request, ack, flags);
863  free_xml(ack);
864  }
865 }
866 
867 /* Client... */
868 
869 #define MIN_MSG_SIZE 12336 /* sizeof(struct qb_ipc_connection_response) */
870 #define MAX_MSG_SIZE 128*1024 /* 128k default */
871 
872 struct crm_ipc_s {
873  struct pollfd pfd;
874 
875  /* the max size we can send/receive over ipc */
876  unsigned int max_buf_size;
877  /* Size of the allocated 'buffer' */
878  unsigned int buf_size;
879  int msg_size;
880  int need_reply;
881  char *buffer;
882  char *name;
883 
884  qb_ipcc_connection_t *ipc;
885 
886 };
887 
888 static unsigned int
889 pick_ipc_buffer(unsigned int max)
890 {
891  static unsigned int global_max = 0;
892 
893  if (global_max == 0) {
894  const char *env = getenv("PCMK_ipc_buffer");
895 
896  if (env) {
897  int env_max = crm_parse_int(env, "0");
898 
899  global_max = (env_max > 0)? QB_MAX(MIN_MSG_SIZE, env_max) : MAX_MSG_SIZE;
900 
901  } else {
902  global_max = MAX_MSG_SIZE;
903  }
904  }
905 
906  return QB_MAX(max, global_max);
907 }
908 
909 crm_ipc_t *
910 crm_ipc_new(const char *name, size_t max_size)
911 {
912  crm_ipc_t *client = NULL;
913 
914  client = calloc(1, sizeof(crm_ipc_t));
915 
916  client->name = strdup(name);
917  client->buf_size = pick_ipc_buffer(max_size);
918  client->buffer = malloc(client->buf_size);
919 
920  /* Clients initiating connection pick the max buf size */
921  client->max_buf_size = client->buf_size;
922 
923  client->pfd.fd = -1;
924  client->pfd.events = POLLIN;
925  client->pfd.revents = 0;
926 
927  return client;
928 }
929 
937 bool
939 {
940  client->need_reply = FALSE;
941  client->ipc = qb_ipcc_connect(client->name, client->buf_size);
942 
943  if (client->ipc == NULL) {
944  crm_debug("Could not establish %s connection: %s (%d)", client->name, pcmk_strerror(errno), errno);
945  return FALSE;
946  }
947 
948  client->pfd.fd = crm_ipc_get_fd(client);
949  if (client->pfd.fd < 0) {
950  crm_debug("Could not obtain file descriptor for %s connection: %s (%d)", client->name, pcmk_strerror(errno), errno);
951  return FALSE;
952  }
953 
954  qb_ipcc_context_set(client->ipc, client);
955 
956 #ifdef HAVE_IPCS_GET_BUFFER_SIZE
957  client->max_buf_size = qb_ipcc_get_buffer_size(client->ipc);
958  if (client->max_buf_size > client->buf_size) {
959  free(client->buffer);
960  client->buffer = calloc(1, client->max_buf_size);
961  client->buf_size = client->max_buf_size;
962  }
963 #endif
964 
965  return TRUE;
966 }
967 
968 void
970 {
971  if (client) {
972  crm_trace("Disconnecting %s IPC connection %p (%p)", client->name, client, client->ipc);
973 
974  if (client->ipc) {
975  qb_ipcc_connection_t *ipc = client->ipc;
976 
977  client->ipc = NULL;
978  qb_ipcc_disconnect(ipc);
979  }
980  }
981 }
982 
983 void
985 {
986  if (client) {
987  if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
988  crm_notice("Destroying an active IPC connection to %s", client->name);
989  /* The next line is basically unsafe
990  *
991  * If this connection was attached to mainloop and mainloop is active,
992  * the 'disconnected' callback will end up back here and we'll end
993  * up free'ing the memory twice - something that can still happen
994  * even without this if we destroy a connection and it closes before
995  * we call exit
996  */
997  /* crm_ipc_close(client); */
998  }
999  crm_trace("Destroying IPC connection to %s: %p", client->name, client);
1000  free(client->buffer);
1001  free(client->name);
1002  free(client);
1003  }
1004 }
1005 
1006 int
1008 {
1009  int fd = 0;
1010 
1011  if (client && client->ipc && (qb_ipcc_fd_get(client->ipc, &fd) == 0)) {
1012  return fd;
1013  }
1014  errno = EINVAL;
1015  crm_perror(LOG_ERR, "Could not obtain file IPC descriptor for %s",
1016  (client? client->name : "unspecified client"));
1017  return -errno;
1018 }
1019 
1020 bool
1022 {
1023  bool rc = FALSE;
1024 
1025  if (client == NULL) {
1026  crm_trace("No client");
1027  return FALSE;
1028 
1029  } else if (client->ipc == NULL) {
1030  crm_trace("No connection");
1031  return FALSE;
1032 
1033  } else if (client->pfd.fd < 0) {
1034  crm_trace("Bad descriptor");
1035  return FALSE;
1036  }
1037 
1038  rc = qb_ipcc_is_connected(client->ipc);
1039  if (rc == FALSE) {
1040  client->pfd.fd = -EINVAL;
1041  }
1042  return rc;
1043 }
1044 
1052 int
1054 {
1055  int rc;
1056 
1057  CRM_ASSERT(client != NULL);
1058 
1059  if (crm_ipc_connected(client) == FALSE) {
1060  return -ENOTCONN;
1061  }
1062 
1063  client->pfd.revents = 0;
1064  rc = poll(&(client->pfd), 1, 0);
1065  return (rc < 0)? -errno : rc;
1066 }
1067 
1068 static int
1069 crm_ipc_decompress(crm_ipc_t * client)
1070 {
1071  struct crm_ipc_response_header *header = (struct crm_ipc_response_header *)(void*)client->buffer;
1072 
1073  if (header->size_compressed) {
1074  int rc = 0;
1075  unsigned int size_u = 1 + header->size_uncompressed;
1076  /* never let buf size fall below our max size required for ipc reads. */
1077  unsigned int new_buf_size = QB_MAX((hdr_offset + size_u), client->max_buf_size);
1078  char *uncompressed = calloc(1, new_buf_size);
1079 
1080  crm_trace("Decompressing message data %u bytes into %u bytes",
1081  header->size_compressed, size_u);
1082 
1083  rc = BZ2_bzBuffToBuffDecompress(uncompressed + hdr_offset, &size_u,
1084  client->buffer + hdr_offset, header->size_compressed, 1, 0);
1085 
1086  if (rc != BZ_OK) {
1087  crm_err("Decompression failed: %s " CRM_XS " bzerror=%d",
1088  bz2_strerror(rc), rc);
1089  free(uncompressed);
1090  return -EILSEQ;
1091  }
1092 
1093  /*
1094  * This assert no longer holds true. For an identical msg, some clients may
1095  * require compression, and others may not. If that same msg (event) is sent
1096  * to multiple clients, it could result in some clients receiving a compressed
1097  * msg even though compression was not explicitly required for them.
1098  *
1099  * CRM_ASSERT((header->size_uncompressed + hdr_offset) >= ipc_buffer_max);
1100  */
1101  CRM_ASSERT(size_u == header->size_uncompressed);
1102 
1103  memcpy(uncompressed, client->buffer, hdr_offset); /* Preserve the header */
1104  header = (struct crm_ipc_response_header *)(void*)uncompressed;
1105 
1106  free(client->buffer);
1107  client->buf_size = new_buf_size;
1108  client->buffer = uncompressed;
1109  }
1110 
1111  CRM_ASSERT(client->buffer[hdr_offset + header->size_uncompressed - 1] == 0);
1112  return pcmk_ok;
1113 }
1114 
1115 long
1117 {
1118  struct crm_ipc_response_header *header = NULL;
1119 
1120  CRM_ASSERT(client != NULL);
1121  CRM_ASSERT(client->ipc != NULL);
1122  CRM_ASSERT(client->buffer != NULL);
1123 
1124  crm_ipc_init();
1125 
1126  client->buffer[0] = 0;
1127  client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1128  client->buf_size, 0);
1129  if (client->msg_size >= 0) {
1130  int rc = crm_ipc_decompress(client);
1131 
1132  if (rc != pcmk_ok) {
1133  return rc;
1134  }
1135 
1136  header = (struct crm_ipc_response_header *)(void*)client->buffer;
1137  if(header->version > PCMK_IPC_VERSION) {
1138  crm_err("Filtering incompatible v%d IPC message, we only support versions <= %d",
1139  header->version, PCMK_IPC_VERSION);
1140  return -EBADMSG;
1141  }
1142 
1143  crm_trace("Received %s event %d, size=%u, rc=%d, text: %.100s",
1144  client->name, header->qb.id, header->qb.size, client->msg_size,
1145  client->buffer + hdr_offset);
1146 
1147  } else {
1148  crm_trace("No message from %s received: %s", client->name, pcmk_strerror(client->msg_size));
1149  }
1150 
1151  if (crm_ipc_connected(client) == FALSE || client->msg_size == -ENOTCONN) {
1152  crm_err("Connection to %s failed", client->name);
1153  }
1154 
1155  if (header) {
1156  /* Data excluding the header */
1157  return header->size_uncompressed;
1158  }
1159  return -ENOMSG;
1160 }
1161 
1162 const char *
1164 {
1165  CRM_ASSERT(client != NULL);
1166  return client->buffer + sizeof(struct crm_ipc_response_header);
1167 }
1168 
1169 uint32_t
1171 {
1172  struct crm_ipc_response_header *header = NULL;
1173 
1174  CRM_ASSERT(client != NULL);
1175  if (client->buffer == NULL) {
1176  return 0;
1177  }
1178 
1179  header = (struct crm_ipc_response_header *)(void*)client->buffer;
1180  return header->flags;
1181 }
1182 
1183 const char *
1185 {
1186  CRM_ASSERT(client != NULL);
1187  return client->name;
1188 }
1189 
1190 static int
1191 internal_ipc_send_recv(crm_ipc_t * client, const void *iov)
1192 {
1193  int rc = 0;
1194 
1195  do {
1196  rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer, client->buf_size, -1);
1197  } while (rc == -EAGAIN && crm_ipc_connected(client));
1198 
1199  return rc;
1200 }
1201 
1202 static int
1203 internal_ipc_send_request(crm_ipc_t * client, const void *iov, int ms_timeout)
1204 {
1205  int rc = 0;
1206  time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1207 
1208  do {
1209  rc = qb_ipcc_sendv(client->ipc, iov, 2);
1210  } while (rc == -EAGAIN && time(NULL) < timeout && crm_ipc_connected(client));
1211 
1212  return rc;
1213 }
1214 
1215 static int
1216 internal_ipc_get_reply(crm_ipc_t * client, int request_id, int ms_timeout)
1217 {
1218  time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1219  int rc = 0;
1220 
1221  crm_ipc_init();
1222 
1223  /* get the reply */
1224  crm_trace("client %s waiting on reply to msg id %d", client->name, request_id);
1225  do {
1226 
1227  rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1228  if (rc > 0) {
1229  struct crm_ipc_response_header *hdr = NULL;
1230 
1231  int rc = crm_ipc_decompress(client);
1232 
1233  if (rc != pcmk_ok) {
1234  return rc;
1235  }
1236 
1237  hdr = (struct crm_ipc_response_header *)(void*)client->buffer;
1238  if (hdr->qb.id == request_id) {
1239  /* Got it */
1240  break;
1241  } else if (hdr->qb.id < request_id) {
1242  xmlNode *bad = string2xml(crm_ipc_buffer(client));
1243 
1244  crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1245  crm_log_xml_notice(bad, "OldIpcReply");
1246 
1247  } else {
1248  xmlNode *bad = string2xml(crm_ipc_buffer(client));
1249 
1250  crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1251  crm_log_xml_notice(bad, "ImpossibleReply");
1252  CRM_ASSERT(hdr->qb.id <= request_id);
1253  }
1254  } else if (crm_ipc_connected(client) == FALSE) {
1255  crm_err("Server disconnected client %s while waiting for msg id %d", client->name,
1256  request_id);
1257  break;
1258  }
1259 
1260  } while (time(NULL) < timeout);
1261 
1262  return rc;
1263 }
1264 
1265 int
1266 crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, int32_t ms_timeout,
1267  xmlNode ** reply)
1268 {
1269  long rc = 0;
1270  struct iovec *iov;
1271  static uint32_t id = 0;
1272  static int factor = 8;
1273  struct crm_ipc_response_header *header;
1274 
1275  crm_ipc_init();
1276 
1277  if (client == NULL) {
1278  crm_notice("Invalid connection");
1279  return -ENOTCONN;
1280 
1281  } else if (crm_ipc_connected(client) == FALSE) {
1282  /* Don't even bother */
1283  crm_notice("Connection to %s closed", client->name);
1284  return -ENOTCONN;
1285  }
1286 
1287  if (ms_timeout == 0) {
1288  ms_timeout = 5000;
1289  }
1290 
1291  if (client->need_reply) {
1292  crm_trace("Trying again to obtain pending reply from %s", client->name);
1293  rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1294  if (rc < 0) {
1295  crm_warn("Sending to %s (%p) is disabled until pending reply is received", client->name,
1296  client->ipc);
1297  return -EALREADY;
1298 
1299  } else {
1300  crm_notice("Lost reply from %s (%p) finally arrived, sending re-enabled", client->name,
1301  client->ipc);
1302  client->need_reply = FALSE;
1303  }
1304  }
1305 
1306  id++;
1307  CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1308  rc = crm_ipc_prepare(id, message, &iov, client->max_buf_size);
1309  if(rc < 0) {
1310  return rc;
1311  }
1312 
1313  header = iov[0].iov_base;
1314  header->flags |= flags;
1315 
1316  if(is_set(flags, crm_ipc_proxied)) {
1317  /* Don't look for a synchronous response */
1319  }
1320 
1321  if(header->size_compressed) {
1322  if(factor < 10 && (client->max_buf_size / 10) < (rc / factor)) {
1323  crm_notice("Compressed message exceeds %d0%% of the configured ipc limit (%u bytes), "
1324  "consider setting PCMK_ipc_buffer to %u or higher",
1325  factor, client->max_buf_size, 2 * client->max_buf_size);
1326  factor++;
1327  }
1328  }
1329 
1330  crm_trace("Sending from client: %s request id: %d bytes: %u timeout:%d msg...",
1331  client->name, header->qb.id, header->qb.size, ms_timeout);
1332 
1333  if (ms_timeout > 0 || is_not_set(flags, crm_ipc_client_response)) {
1334 
1335  rc = internal_ipc_send_request(client, iov, ms_timeout);
1336 
1337  if (rc <= 0) {
1338  crm_trace("Failed to send from client %s request %d with %u bytes...",
1339  client->name, header->qb.id, header->qb.size);
1340  goto send_cleanup;
1341 
1342  } else if (is_not_set(flags, crm_ipc_client_response)) {
1343  crm_trace("Message sent, not waiting for reply to %d from %s to %u bytes...",
1344  header->qb.id, client->name, header->qb.size);
1345 
1346  goto send_cleanup;
1347  }
1348 
1349  rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout);
1350  if (rc < 0) {
1351  /* No reply, for now, disable sending
1352  *
1353  * The alternative is to close the connection since we don't know
1354  * how to detect and discard out-of-sequence replies
1355  *
1356  * TODO - implement the above
1357  */
1358  client->need_reply = TRUE;
1359  }
1360 
1361  } else {
1362  rc = internal_ipc_send_recv(client, iov);
1363  }
1364 
1365  if (rc > 0) {
1366  struct crm_ipc_response_header *hdr = (struct crm_ipc_response_header *)(void*)client->buffer;
1367 
1368  crm_trace("Received response %d, size=%u, rc=%ld, text: %.200s", hdr->qb.id, hdr->qb.size,
1369  rc, crm_ipc_buffer(client));
1370 
1371  if (reply) {
1372  *reply = string2xml(crm_ipc_buffer(client));
1373  }
1374 
1375  } else {
1376  crm_trace("Response not received: rc=%ld, errno=%d", rc, errno);
1377  }
1378 
1379  send_cleanup:
1380  if (crm_ipc_connected(client) == FALSE) {
1381  crm_notice("Connection to %s closed: %s (%ld)", client->name, pcmk_strerror(rc), rc);
1382 
1383  } else if (rc == -ETIMEDOUT) {
1384  crm_warn("Request %d to %s (%p) failed: %s (%ld) after %dms",
1385  header->qb.id, client->name, client->ipc, pcmk_strerror(rc), rc, ms_timeout);
1386  crm_write_blackbox(0, NULL);
1387 
1388  } else if (rc <= 0) {
1389  crm_warn("Request %d to %s (%p) failed: %s (%ld)",
1390  header->qb.id, client->name, client->ipc, pcmk_strerror(rc), rc);
1391  }
1392 
1393  pcmk_free_ipc_event(iov);
1394  return rc;
1395 }
1396 
1397 /* Utils */
1398 
1399 xmlNode *
1400 create_hello_message(const char *uuid,
1401  const char *client_name, const char *major_version, const char *minor_version)
1402 {
1403  xmlNode *hello_node = NULL;
1404  xmlNode *hello = NULL;
1405 
1406  if (uuid == NULL || strlen(uuid) == 0
1407  || client_name == NULL || strlen(client_name) == 0
1408  || major_version == NULL || strlen(major_version) == 0
1409  || minor_version == NULL || strlen(minor_version) == 0) {
1410  crm_err("Missing fields, Hello message will not be valid.");
1411  return NULL;
1412  }
1413 
1414  hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
1415  crm_xml_add(hello_node, "major_version", major_version);
1416  crm_xml_add(hello_node, "minor_version", minor_version);
1417  crm_xml_add(hello_node, "client_name", client_name);
1418  crm_xml_add(hello_node, "client_uuid", uuid);
1419 
1420  crm_trace("creating hello message");
1421  hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
1422  free_xml(hello_node);
1423 
1424  return hello;
1425 }
#define F_CRM_TASK
Definition: msg_xml.h:50
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:165
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc.c:1163
void pcmk_free_ipc_event(struct iovec *event)
Free an I/O vector created by crm_ipc_prepare()
Definition: ipc.c:410
#define F_CRM_REFERENCE
Definition: msg_xml.h:56
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
Definition: logging.c:432
A dumping ground.
client_type
Definition: ipcs.h:27
#define F_TYPE
Definition: msg_xml.h:28
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc.c:969
#define crm_notice(fmt, args...)
Definition: logging.h:251
const char * pcmk_strerror(int rc)
Definition: results.c:184
const char * bz2_strerror(int rc)
Definition: results.c:425
char * crm_generate_uuid(void)
Definition: utils.c:1075
GQueue * event_queue
Definition: ipcs.h:80
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc.c:1170
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Definition: ipc.c:1266
#define F_CRM_HOST_TO
Definition: msg_xml.h:51
#define XML_TAG_OPTIONS
Definition: msg_xml.h:110
crm_client_t * crm_client_get(qb_ipcs_connection_t *c)
Definition: ipc.c:175
uint32_t flags
Definition: ipcs.h:76
qb_ipcs_connection_t * ipcs
Definition: ipcs.h:87
#define F_CRM_MSG_TYPE
Definition: msg_xml.h:52
uint32_t size
Definition: internal.h:84
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:320
int request_id
Definition: ipcs.h:75
#define CRM_FEATURE_SET
Definition: crm.h:30
#define F_CRM_HOST_FROM
Definition: msg_xml.h:55
#define T_CRM
Definition: msg_xml.h:40
long long crm_int_helper(const char *text, char **end_text)
Definition: strings.c:32
bool crm_set_client_queue_max(crm_client_t *client, const char *qmax)
Raise IPC eviction threshold for a client, if allowed.
Definition: ipc.c:485
crm_client_t * crm_client_get_by_id(const char *id)
Definition: ipc.c:186
xmlNode * create_reply_adv(xmlNode *original_request, xmlNode *xml_response_data, const char *origin)
Definition: ipc.c:118
char * buffer
Definition: ipcs.h:37
unsigned int queue_max
Definition: ipcs.h:92
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:212
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc.c:938
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:107
#define PCMK_IPC_VERSION
Definition: ipc.c:27
struct crm_remote_s * remote
Definition: ipcs.h:89
int crm_user_lookup(const char *name, uid_t *uid, gid_t *gid)
Definition: utils.c:400
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:151
void crm_client_destroy(crm_client_t *c)
Definition: ipc.c:435
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc.c:1007
void crm_client_init(void)
Definition: ipc.c:237
#define clear_bit(word, bit)
Definition: crm_internal.h:166
void crm_client_disconnect_all(qb_ipcs_service_t *service)
Definition: ipc.c:259
ssize_t crm_ipc_prepare(uint32_t request, xmlNode *message, struct iovec **result, uint32_t max_send_size)
Definition: ipc.c:682
char * user
Definition: ipcs.h:69
ssize_t crm_ipcs_flush_events(crm_client_t *c)
Definition: ipc.c:594
xmlNode * string2xml(const char *input)
Definition: xml.c:2056
#define MAX_MSG_SIZE
Definition: ipc.c:870
#define XML_ATTR_REQUEST
Definition: msg_xml.h:113
ssize_t crm_ipcs_sendv(crm_client_t *c, struct iovec *iov, enum crm_ipc_flags flags)
Definition: ipc.c:756
const char * crm_client_type_text(enum client_type client_type)
Definition: ipc.c:220
#define crm_warn(fmt, args...)
Definition: logging.h:250
crm_client_t * crm_client_new(qb_ipcs_connection_t *c, uid_t uid_client, gid_t gid_client)
Definition: ipc.c:350
#define set_bit(word, bit)
Definition: crm_internal.h:165
#define crm_debug(fmt, args...)
Definition: logging.h:254
#define F_CRM_SYS_TO
Definition: msg_xml.h:53
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:56
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:360
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc.c:1184
GHashTable * client_connections
Definition: ipc.c:172
unsigned int crm_ipc_default_buffer_size(void)
Definition: ipc.c:56
#define crm_trace(fmt, args...)
Definition: logging.h:255
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc.c:984
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1888
#define CRM_DAEMON_USER
Definition: config.h:47
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: xml.c:2510
void free_xml(xmlNode *child)
Definition: xml.c:2012
void crm_ipcs_send_ack(crm_client_t *c, uint32_t request, uint32_t flags, const char *tag, const char *function, int line)
Definition: ipc.c:852
unsigned int queue_backlog
Definition: ipcs.h:91
xmlNode * crm_ipcs_recv(crm_client_t *c, void *data, size_t size, uint32_t *id, uint32_t *flags)
Definition: ipc.c:509
int auth_timeout
Definition: ipcs.h:40
#define F_CRM_DATA
Definition: msg_xml.h:49
#define CRM_XS
Definition: logging.h:43
crm_client_t * crm_client_alloc(void *key)
Allocate a new crm_client_t object and generate its ID.
Definition: ipc.c:341
bool crm_compress_string(const char *data, int length, int max, char **result, unsigned int *result_len)
Definition: strings.c:411
ssize_t crm_ipcs_send(crm_client_t *c, uint32_t request, xmlNode *message, enum crm_ipc_flags flags)
Definition: ipc.c:829
#define PCMK_IPC_DEFAULT_QUEUE_MAX
Definition: ipc.c:30
uint pid
Definition: ipcs.h:62
int event_timer
Definition: ipcs.h:79
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:227
xmlNode * create_hello_message(const char *uuid, const char *client_name, const char *major_version, const char *minor_version)
Definition: ipc.c:1400
#define CRM_OP_HELLO
Definition: crm.h:111
#define crm_err(fmt, args...)
Definition: logging.h:249
#define CRM_ASSERT(expr)
Definition: results.h:20
#define F_CRM_SYS_FROM
Definition: msg_xml.h:54
#define crm_log_xml_notice(xml, text)
Definition: logging.h:260
char * dump_xml_unformatted(xmlNode *msg)
Definition: xml.c:3164
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc.c:1053
#define uint32_t
Definition: stdint.in.h:158
#define XML_ATTR_RESPONSE
Definition: msg_xml.h:114
char data[0]
Definition: internal.h:90
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc.c:1116
char * id
Definition: ipcs.h:67
#define uint8_t
Definition: stdint.in.h:144
#define pcmk_ok
Definition: results.h:35
Wrappers for and extensions to libqb IPC.
char * generate_hash_key(const char *crm_msg_reference, const char *sys)
Definition: utils.c:390
#define F_CRM_ORIGIN
Definition: msg_xml.h:58
int crm_ipcs_client_pid(qb_ipcs_connection_t *c)
Definition: ipc.c:499
#define crm_log_xml_trace(xml, text)
Definition: logging.h:263
void crm_client_cleanup(void)
Definition: ipc.c:246
enum client_type kind
Definition: ipcs.h:85
const char * crm_client_name(crm_client_t *c)
Definition: ipc.c:206
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc.c:1021
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Definition: ipc.c:910
char * name
Definition: ipcs.h:68
crm_ipc_flags
Definition: ipc.h:37
xmlNode * create_request_adv(const char *task, xmlNode *msg_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *origin)
Definition: ipc.c:73
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition: ipc.h:30
char * uid2username(uid_t uid)
#define F_CRM_VERSION
Definition: msg_xml.h:57
uint32_t version
Definition: remote.c:146
uint64_t flags
Definition: remote.c:148
#define MIN_MSG_SIZE
Definition: ipc.c:869
enum crm_ais_msg_types type
Definition: internal.h:83
#define int32_t
Definition: stdint.in.h:157