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