11 #include <dbus/dbus.h>
14 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
16 static GList *conn_dispatches = NULL;
18 struct db_getall_data {
23 void (*callback)(
const char *
name,
const char *value,
void *userdata);
27 free_db_getall_data(
struct db_getall_data *
data)
39 DBusConnection *connection;
41 dbus_error_init(&err);
42 connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
43 if (dbus_error_is_set(&err)) {
44 crm_err(
"Could not connect to System DBus: %s", err.message);
45 dbus_error_free(&err);
81 dbus_error_init(&error);
84 dbus_set_error_const(&error,
"org.clusterlabs.pacemaker.NoRequest",
87 }
else if(reply == NULL) {
88 dbus_set_error_const(&error,
"org.clusterlabs.pacemaker.NoReply",
93 int dtype = dbus_message_get_type(reply);
97 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
98 dbus_message_iter_init(reply, &args);
99 sig = dbus_message_iter_get_signature(&args);
100 crm_trace(
"DBus call returned output args '%s'", sig);
103 case DBUS_MESSAGE_TYPE_INVALID:
104 dbus_set_error_const(&error,
105 "org.clusterlabs.pacemaker.InvalidReply",
108 case DBUS_MESSAGE_TYPE_METHOD_CALL:
109 dbus_set_error_const(&error,
110 "org.clusterlabs.pacemaker.InvalidReply.Method",
111 "Invalid reply (method call)");
113 case DBUS_MESSAGE_TYPE_SIGNAL:
114 dbus_set_error_const(&error,
115 "org.clusterlabs.pacemaker.InvalidReply.Signal",
116 "Invalid reply (signal)");
118 case DBUS_MESSAGE_TYPE_ERROR:
119 dbus_set_error_from_message(&error, reply);
122 dbus_set_error(&error,
123 "org.clusterlabs.pacemaker.InvalidReply.Type",
124 "Unknown reply type %d", dtype);
128 if (dbus_error_is_set(&error)) {
129 crm_trace(
"DBus reply indicated error '%s' (%s)",
130 error.name, error.message);
132 dbus_error_init(ret);
133 dbus_move_error(&error, ret);
135 dbus_error_free(&error);
162 const char *method = NULL;
163 DBusMessage *reply = NULL;
164 DBusPendingCall* pending = NULL;
166 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
167 method = dbus_message_get_member (msg);
171 dbus_error_init(error);
180 if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
182 dbus_set_error(error,
"org.clusterlabs.pacemaker.SendFailed",
183 "Could not queue DBus '%s' request", method);
188 dbus_connection_flush(connection);
192 dbus_pending_call_block(pending);
195 reply = dbus_pending_call_steal_reply(pending);
202 dbus_pending_call_unref(pending);
224 void(*done)(DBusPendingCall *pending,
void *user_data),
227 const char *method = NULL;
228 DBusPendingCall* pending = NULL;
231 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
232 method = dbus_message_get_member (msg);
241 if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
242 crm_err(
"Send with reply failed for %s", method);
245 }
else if (pending == NULL) {
246 crm_err(
"No pending call found for %s: Connection to System DBus may be closed", method);
251 if (dbus_pending_call_get_completed(pending)) {
252 crm_info(
"DBus %s call completed too soon", method);
256 done(pending, user_data);
259 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
264 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
271 const char *
function,
int line)
274 DBusMessageIter lfield;
277 if(dbus_message_iter_init(msg, &lfield)) {
284 "Empty parameter list in reply expecting '%c'", expected);
288 dtype = dbus_message_iter_get_arg_type(field);
290 if(dtype != expected) {
291 DBusMessageIter args;
294 dbus_message_iter_init(msg, &args);
295 sig = dbus_message_iter_get_signature(&args);
297 "Unexpected DBus type, expected %c in '%s' instead of %c",
298 expected, sig, dtype);
307 pcmk_dbus_lookup_result(DBusMessage *reply,
struct db_getall_data *
data)
311 DBusMessageIter dict;
312 DBusMessageIter args;
315 crm_err(
"Cannot get properties from %s for %s: %s",
316 data->target, data->object, error.message);
317 dbus_error_free(&error);
321 dbus_message_iter_init(reply, &args);
323 crm_err(
"Invalid reply from %s for %s", data->target, data->object);
327 dbus_message_iter_recurse(&args, &dict);
328 while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
332 DBusBasicValue value;
335 dbus_message_iter_next (&dict);
339 dbus_message_iter_recurse(&dict, &sv);
340 while (dbus_message_iter_get_arg_type (&sv) != DBUS_TYPE_INVALID) {
341 int dtype = dbus_message_iter_get_arg_type(&sv);
344 case DBUS_TYPE_STRING:
345 dbus_message_iter_get_basic(&sv, &name);
347 if(data->name && strcmp(name.str, data->name) != 0) {
348 dbus_message_iter_next (&sv);
351 case DBUS_TYPE_VARIANT:
352 dbus_message_iter_recurse(&sv, &v);
354 dbus_message_iter_get_basic(&v, &value);
356 crm_trace(
"Property %s[%s] is '%s'", data->object, name.str, value.str);
358 data->callback(name.str, value.str, data->userdata);
362 output = strdup(value.str);
373 dbus_message_iter_next (&sv);
376 dbus_message_iter_next (&dict);
379 if(data->name && data->callback) {
380 crm_trace(
"No value for property %s[%s]", data->object, data->name);
381 data->callback(data->name, NULL, data->userdata);
385 free_db_getall_data(data);
390 pcmk_dbus_lookup_cb(DBusPendingCall *pending,
void *user_data)
392 DBusMessage *reply = NULL;
396 reply = dbus_pending_call_steal_reply(pending);
399 value = pcmk_dbus_lookup_result(reply, user_data);
403 dbus_message_unref(reply);
409 const char *obj,
const gchar * iface,
const char *name,
410 void (*callback)(
const char *name,
const char *value,
void *userdata),
411 void *userdata, DBusPendingCall **pending,
int timeout)
414 const char *method =
"GetAll";
416 struct db_getall_data *query_data = NULL;
418 crm_debug(
"Calling: %s on %s", method, target);
419 msg = dbus_message_new_method_call(target,
424 crm_err(
"Call to %s failed: No message", method);
428 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
430 query_data = malloc(
sizeof(
struct db_getall_data));
431 if(query_data == NULL) {
432 crm_err(
"Call to %s failed: malloc failed", method);
436 query_data->target = strdup(target);
437 query_data->object = strdup(obj);
438 query_data->callback = callback;
439 query_data->userdata = userdata;
440 query_data->name = NULL;
443 query_data->name = strdup(name);
446 if (query_data->callback) {
447 DBusPendingCall *local_pending;
449 local_pending =
pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb,
450 query_data, timeout);
451 if (local_pending == NULL) {
453 free_db_getall_data(query_data);
458 *pending = local_pending;
464 output = pcmk_dbus_lookup_result(reply, query_data);
467 dbus_message_unref(reply);
471 dbus_message_unref(msg);
477 pcmk_dbus_connection_dispatch_status(DBusConnection *connection,
478 DBusDispatchStatus new_status,
void *data)
480 crm_trace(
"New status %d for connection %p", new_status, connection);
481 if (new_status == DBUS_DISPATCH_DATA_REMAINS){
482 conn_dispatches = g_list_prepend(conn_dispatches, connection);
487 pcmk_dbus_connections_dispatch(
void)
491 for (gIter = conn_dispatches; gIter != NULL; gIter = gIter->next) {
492 DBusConnection *connection = gIter->data;
494 while (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS) {
495 crm_trace(
"Dispatching for connection %p", connection);
496 dbus_connection_dispatch(connection);
500 g_list_free(conn_dispatches);
501 conn_dispatches = NULL;
507 dbus_watch_flags_to_string(
int flags)
509 const char *watch_type;
511 if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE)) {
512 watch_type =
"readwrite";
513 }
else if (flags & DBUS_WATCH_READABLE) {
515 }
else if (flags & DBUS_WATCH_WRITABLE) {
516 watch_type =
"write";
518 watch_type =
"not read or write";
524 pcmk_dbus_watch_dispatch(gpointer userdata)
527 DBusWatch *watch = userdata;
528 int flags = dbus_watch_get_flags(watch);
529 bool enabled = dbus_watch_get_enabled (watch);
532 crm_trace(
"Dispatching client %p: %s", client, dbus_watch_flags_to_string(flags));
533 if (enabled && (flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) {
534 oom = !dbus_watch_handle(watch, flags);
537 oom = !dbus_watch_handle(watch, DBUS_WATCH_ERROR);
540 if(flags != dbus_watch_get_flags(watch)) {
541 flags = dbus_watch_get_flags(watch);
542 crm_trace(
"Dispatched client %p: %s (%d)", client,
543 dbus_watch_flags_to_string(flags), flags);
547 crm_err(
"DBus encountered OOM while attempting to dispatch %p (%s)",
548 client, dbus_watch_flags_to_string(flags));
551 pcmk_dbus_connections_dispatch();
558 pcmk_dbus_watch_destroy(gpointer userdata)
566 .
dispatch = pcmk_dbus_watch_dispatch,
567 .destroy = pcmk_dbus_watch_destroy,
571 pcmk_dbus_watch_add(DBusWatch *watch,
void *data)
573 int fd = dbus_watch_get_unix_fd(watch);
576 "dbus", G_PRIORITY_DEFAULT, fd, watch, &pcmk_dbus_cb);
578 crm_trace(
"Added watch %p with fd=%d to client %p", watch, fd, client);
579 dbus_watch_set_data(watch, client, NULL);
584 pcmk_dbus_watch_toggle(DBusWatch *watch,
void *data)
588 client, (dbus_watch_get_enabled(watch)?
"enabled" :
"disabled"));
593 pcmk_dbus_watch_remove(DBusWatch *watch,
void *data)
597 crm_trace(
"Removed client %p (%p)", client, data);
602 pcmk_dbus_timeout_dispatch(gpointer data)
604 crm_info(
"Timeout %p expired", data);
605 dbus_timeout_handle(data);
610 pcmk_dbus_timeout_add(DBusTimeout *
timeout,
void *data)
612 guint
id = g_timeout_add(dbus_timeout_get_interval(timeout),
613 pcmk_dbus_timeout_dispatch, timeout);
615 crm_trace(
"Adding timeout %p (%d)", timeout, dbus_timeout_get_interval(timeout));
618 dbus_timeout_set_data(timeout, GUINT_TO_POINTER(
id), NULL);
624 pcmk_dbus_timeout_remove(DBusTimeout *timeout,
void *data)
626 void *vid = dbus_timeout_get_data(timeout);
627 guint
id = GPOINTER_TO_UINT(vid);
629 crm_trace(
"Removing timeout %p (%p)", timeout, data);
633 dbus_timeout_set_data(timeout, 0, NULL);
638 pcmk_dbus_timeout_toggle(DBusTimeout *timeout,
void *data)
640 bool enabled = dbus_timeout_get_enabled(timeout);
642 crm_trace(
"Toggling timeout for %p to %s", timeout, enabled?
"off":
"on");
645 pcmk_dbus_timeout_add(timeout, data);
647 pcmk_dbus_timeout_remove(timeout, data);
656 dbus_connection_set_exit_on_disconnect(c, FALSE);
657 dbus_connection_set_timeout_functions(c, pcmk_dbus_timeout_add,
658 pcmk_dbus_timeout_remove,
659 pcmk_dbus_timeout_toggle, NULL, NULL);
660 dbus_connection_set_watch_functions(c, pcmk_dbus_watch_add,
661 pcmk_dbus_watch_remove,
662 pcmk_dbus_watch_toggle, NULL, NULL);
663 dbus_connection_set_dispatch_status_function(c, pcmk_dbus_connection_dispatch_status, NULL, NULL);
664 pcmk_dbus_connection_dispatch_status(c, dbus_connection_get_dispatch_status(c), NULL);
#define crm_notice(fmt, args...)
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
#define BUS_PROPERTY_IFACE
void pcmk_dbus_disconnect(DBusConnection *connection)
#define DBUS_TIMEOUT_USE_DEFAULT
struct mainloop_io_s mainloop_io_t
void pcmk_dbus_connection_setup_with_select(DBusConnection *c)
int(* dispatch)(gpointer userdata)
#define CRM_LOG_ASSERT(expr)
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
bool pcmk_dbus_find_error(DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
#define crm_debug(fmt, args...)
#define crm_trace(fmt, args...)
char * pcmk_dbus_get_property(DBusConnection *connection, const char *target, const char *obj, const gchar *iface, const char *name, void(*callback)(const char *name, const char *value, void *userdata), void *userdata, DBusPendingCall **pending, int timeout)
DBusPendingCall * pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection, void(*done)(DBusPendingCall *pending, void *user_data), void *user_data, int timeout)
DBusConnection * pcmk_dbus_connect(void)
#define crm_err(fmt, args...)
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
void mainloop_del_fd(mainloop_io_t *client)
DBusMessage * pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error, int timeout)
#define crm_info(fmt, args...)
struct mainloop_fd_callbacks pcmk_dbus_cb