11 #include <dbus/dbus.h> 14 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties" 16 struct db_getall_data {
21 void (*callback)(
const char *name,
const char *value,
void *userdata);
28 DBusConnection *connection;
30 dbus_error_init(&err);
31 connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
32 if (dbus_error_is_set(&err)) {
33 crm_err(
"Could not connect to System DBus: %s", err.message);
34 dbus_error_free(&err);
70 dbus_error_init(&error);
73 dbus_set_error_const(&error,
"org.clusterlabs.pacemaker.NoRequest",
76 }
else if(reply == NULL) {
77 dbus_set_error_const(&error,
"org.clusterlabs.pacemaker.NoReply",
82 int dtype = dbus_message_get_type(reply);
86 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
87 dbus_message_iter_init(reply, &args);
88 sig = dbus_message_iter_get_signature(&args);
89 crm_trace(
"DBus call returned output args '%s'", sig);
92 case DBUS_MESSAGE_TYPE_INVALID:
93 dbus_set_error_const(&error,
94 "org.clusterlabs.pacemaker.InvalidReply",
97 case DBUS_MESSAGE_TYPE_METHOD_CALL:
98 dbus_set_error_const(&error,
99 "org.clusterlabs.pacemaker.InvalidReply.Method",
100 "Invalid reply (method call)");
102 case DBUS_MESSAGE_TYPE_SIGNAL:
103 dbus_set_error_const(&error,
104 "org.clusterlabs.pacemaker.InvalidReply.Signal",
105 "Invalid reply (signal)");
107 case DBUS_MESSAGE_TYPE_ERROR:
108 dbus_set_error_from_message(&error, reply);
111 dbus_set_error(&error,
112 "org.clusterlabs.pacemaker.InvalidReply.Type",
113 "Unknown reply type %d", dtype);
117 if (dbus_error_is_set(&error)) {
118 crm_trace(
"DBus reply indicated error '%s' (%s)",
119 error.name, error.message);
121 dbus_error_init(ret);
122 dbus_move_error(&error, ret);
124 dbus_error_free(&error);
149 DBusError *error,
int timeout)
151 const char *method = NULL;
152 DBusMessage *reply = NULL;
153 DBusPendingCall* pending = NULL;
155 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
156 method = dbus_message_get_member (msg);
160 dbus_error_init(error);
169 if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
171 dbus_set_error(error,
"org.clusterlabs.pacemaker.SendFailed",
172 "Could not queue DBus '%s' request", method);
177 dbus_connection_flush(connection);
181 dbus_pending_call_block(pending);
184 reply = dbus_pending_call_steal_reply(pending);
191 dbus_pending_call_unref(pending);
199 void(*done)(DBusPendingCall *pending,
void *user_data),
200 void *user_data,
int timeout)
202 const char *method = NULL;
203 DBusPendingCall* pending = NULL;
206 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
207 method = dbus_message_get_member (msg);
216 if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
217 crm_err(
"Send with reply failed for %s", method);
220 }
else if (pending == NULL) {
221 crm_err(
"No pending call found for %s: Connection to System DBus may be closed", method);
226 if (dbus_pending_call_get_completed(pending)) {
227 crm_info(
"DBus %s call completed too soon", method);
231 done(pending, user_data);
234 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
239 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
246 const char *
function,
int line)
249 DBusMessageIter lfield;
252 if(dbus_message_iter_init(msg, &lfield)) {
259 "Empty parameter list in reply expecting '%c'", expected);
263 dtype = dbus_message_iter_get_arg_type(field);
265 if(dtype != expected) {
266 DBusMessageIter args;
269 dbus_message_iter_init(msg, &args);
270 sig = dbus_message_iter_get_signature(&args);
272 "Unexpected DBus type, expected %c in '%s' instead of %c",
273 expected, sig, dtype);
282 pcmk_dbus_lookup_result(DBusMessage *reply,
struct db_getall_data *
data)
286 DBusMessageIter dict;
287 DBusMessageIter args;
290 crm_err(
"Cannot get properties from %s for %s: %s",
291 data->target, data->object, error.message);
292 dbus_error_free(&error);
296 dbus_message_iter_init(reply, &args);
298 crm_err(
"Invalid reply from %s for %s", data->target, data->object);
302 dbus_message_iter_recurse(&args, &dict);
303 while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
307 DBusBasicValue value;
310 dbus_message_iter_next (&dict);
314 dbus_message_iter_recurse(&dict, &sv);
315 while (dbus_message_iter_get_arg_type (&sv) != DBUS_TYPE_INVALID) {
316 int dtype = dbus_message_iter_get_arg_type(&sv);
319 case DBUS_TYPE_STRING:
320 dbus_message_iter_get_basic(&sv, &name);
322 if(data->name && strcmp(name.str, data->name) != 0) {
323 dbus_message_iter_next (&sv);
326 case DBUS_TYPE_VARIANT:
327 dbus_message_iter_recurse(&sv, &v);
329 dbus_message_iter_get_basic(&v, &value);
331 crm_trace(
"Property %s[%s] is '%s'", data->object, name.str, value.str);
333 data->callback(name.str, value.str, data->userdata);
337 output = strdup(value.str);
348 dbus_message_iter_next (&sv);
351 dbus_message_iter_next (&dict);
354 if(data->name && data->callback) {
355 crm_trace(
"No value for property %s[%s]", data->object, data->name);
356 data->callback(data->name, NULL, data->userdata);
369 pcmk_dbus_lookup_cb(DBusPendingCall *pending,
void *user_data)
371 DBusMessage *reply = NULL;
375 reply = dbus_pending_call_steal_reply(pending);
378 value = pcmk_dbus_lookup_result(reply, user_data);
382 dbus_message_unref(reply);
388 const char *obj,
const gchar * iface,
const char *name,
389 void (*callback)(
const char *name,
const char *value,
void *userdata),
390 void *userdata, DBusPendingCall **pending,
int timeout)
393 const char *method =
"GetAll";
395 struct db_getall_data *query_data = NULL;
397 crm_debug(
"Calling: %s on %s", method, target);
398 msg = dbus_message_new_method_call(target,
403 crm_err(
"Call to %s failed: No message", method);
407 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
409 query_data = malloc(
sizeof(
struct db_getall_data));
410 if(query_data == NULL) {
411 crm_err(
"Call to %s failed: malloc failed", method);
415 query_data->target = strdup(target);
416 query_data->object = strdup(obj);
417 query_data->callback = callback;
418 query_data->userdata = userdata;
419 query_data->name = NULL;
422 query_data->name = strdup(name);
425 if(query_data->callback) {
426 DBusPendingCall* _pending;
427 _pending =
pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data, timeout);
428 if (pending != NULL) {
435 output = pcmk_dbus_lookup_result(reply, query_data);
438 dbus_message_unref(reply);
442 dbus_message_unref(msg);
448 pcmk_dbus_connection_dispatch(DBusConnection *connection,
449 DBusDispatchStatus new_status,
void *data)
451 crm_trace(
"status %d for %p", new_status, data);
452 if (new_status == DBUS_DISPATCH_DATA_REMAINS){
453 dbus_connection_dispatch(connection);
455 while (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS) {
456 dbus_connection_dispatch(connection);
464 dbus_watch_flags_to_string(
int flags)
466 const char *watch_type;
468 if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE)) {
469 watch_type =
"readwrite";
470 }
else if (flags & DBUS_WATCH_READABLE) {
472 }
else if (flags & DBUS_WATCH_WRITABLE) {
473 watch_type =
"write";
475 watch_type =
"not read or write";
481 pcmk_dbus_watch_dispatch(gpointer userdata)
484 DBusWatch *watch = userdata;
485 int flags = dbus_watch_get_flags(watch);
486 bool enabled = dbus_watch_get_enabled (watch);
489 crm_trace(
"Dispatching client %p: %s", client, dbus_watch_flags_to_string(flags));
490 if (enabled && is_set(flags, DBUS_WATCH_READABLE)) {
491 oom = !dbus_watch_handle(watch, flags);
493 }
else if (enabled && is_set(flags, DBUS_WATCH_READABLE)) {
494 oom = !dbus_watch_handle(watch, flags);
497 oom = !dbus_watch_handle(watch, DBUS_WATCH_ERROR);
500 if(flags != dbus_watch_get_flags(watch)) {
501 flags = dbus_watch_get_flags(watch);
502 crm_trace(
"Dispatched client %p: %s (%d)", client,
503 dbus_watch_flags_to_string(flags), flags);
507 crm_err(
"DBus encountered OOM while attempting to dispatch %p (%s)",
508 client, dbus_watch_flags_to_string(flags));
514 pcmk_dbus_watch_destroy(gpointer userdata)
522 .
dispatch = pcmk_dbus_watch_dispatch,
523 .destroy = pcmk_dbus_watch_destroy,
527 pcmk_dbus_watch_add(DBusWatch *watch,
void *data)
529 int fd = dbus_watch_get_unix_fd(watch);
532 "dbus", G_PRIORITY_DEFAULT, fd, watch, &pcmk_dbus_cb);
534 crm_trace(
"Added watch %p with fd=%d to client %p", watch, fd, client);
535 dbus_watch_set_data(watch, client, NULL);
540 pcmk_dbus_watch_toggle(DBusWatch *watch,
void *data)
544 client, (dbus_watch_get_enabled(watch)?
"enabled" :
"disabled"));
549 pcmk_dbus_watch_remove(DBusWatch *watch,
void *data)
553 crm_trace(
"Removed client %p (%p)", client, data);
558 pcmk_dbus_timeout_dispatch(gpointer data)
560 crm_info(
"Timeout %p expired", data);
561 dbus_timeout_handle(data);
566 pcmk_dbus_timeout_add(DBusTimeout *timeout,
void *data)
568 guint
id = g_timeout_add(dbus_timeout_get_interval(timeout),
569 pcmk_dbus_timeout_dispatch, timeout);
571 crm_trace(
"Adding timeout %p (%d)", timeout, dbus_timeout_get_interval(timeout));
574 dbus_timeout_set_data(timeout, GUINT_TO_POINTER(
id), NULL);
580 pcmk_dbus_timeout_remove(DBusTimeout *timeout,
void *data)
582 void *vid = dbus_timeout_get_data(timeout);
583 guint
id = GPOINTER_TO_UINT(vid);
585 crm_trace(
"Removing timeout %p (%p)", timeout, data);
589 dbus_timeout_set_data(timeout, 0, NULL);
594 pcmk_dbus_timeout_toggle(DBusTimeout *timeout,
void *data)
596 bool enabled = dbus_timeout_get_enabled(timeout);
598 crm_trace(
"Toggling timeout for %p to %s", timeout, enabled?
"off":
"on");
601 pcmk_dbus_timeout_add(timeout, data);
603 pcmk_dbus_timeout_remove(timeout, data);
612 dbus_connection_set_exit_on_disconnect(c, FALSE);
613 dbus_connection_set_timeout_functions(c, pcmk_dbus_timeout_add,
614 pcmk_dbus_timeout_remove,
615 pcmk_dbus_timeout_toggle, NULL, NULL);
616 dbus_connection_set_watch_functions(c, pcmk_dbus_watch_add,
617 pcmk_dbus_watch_remove,
618 pcmk_dbus_watch_toggle, NULL, NULL);
619 dbus_connection_set_dispatch_status_function(c, pcmk_dbus_connection_dispatch, NULL, NULL);
620 pcmk_dbus_connection_dispatch(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)
#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)
int(* dispatch)(gpointer userdata)
#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