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