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);
30 DBusConnection *connection;
32 dbus_error_init(&err);
33 connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
34 if (dbus_error_is_set(&err)) {
35 crm_err(
"Could not connect to System DBus: %s", err.message);
36 dbus_error_free(&err);
72 dbus_error_init(&error);
75 dbus_set_error_const(&error,
"org.clusterlabs.pacemaker.NoRequest",
78 }
else if(reply == NULL) {
79 dbus_set_error_const(&error,
"org.clusterlabs.pacemaker.NoReply",
84 int dtype = dbus_message_get_type(reply);
88 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
89 dbus_message_iter_init(reply, &args);
90 sig = dbus_message_iter_get_signature(&args);
91 crm_trace(
"DBus call returned output args '%s'", sig);
94 case DBUS_MESSAGE_TYPE_INVALID:
95 dbus_set_error_const(&error,
96 "org.clusterlabs.pacemaker.InvalidReply",
99 case DBUS_MESSAGE_TYPE_METHOD_CALL:
100 dbus_set_error_const(&error,
101 "org.clusterlabs.pacemaker.InvalidReply.Method",
102 "Invalid reply (method call)");
104 case DBUS_MESSAGE_TYPE_SIGNAL:
105 dbus_set_error_const(&error,
106 "org.clusterlabs.pacemaker.InvalidReply.Signal",
107 "Invalid reply (signal)");
109 case DBUS_MESSAGE_TYPE_ERROR:
110 dbus_set_error_from_message(&error, reply);
113 dbus_set_error(&error,
114 "org.clusterlabs.pacemaker.InvalidReply.Type",
115 "Unknown reply type %d", dtype);
119 if (dbus_error_is_set(&error)) {
120 crm_trace(
"DBus reply indicated error '%s' (%s)",
121 error.name, error.message);
123 dbus_error_init(ret);
124 dbus_move_error(&error, ret);
126 dbus_error_free(&error);
151 DBusError *error,
int timeout)
153 const char *method = NULL;
154 DBusMessage *reply = NULL;
155 DBusPendingCall* pending = NULL;
157 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
158 method = dbus_message_get_member (msg);
162 dbus_error_init(error);
171 if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
173 dbus_set_error(error,
"org.clusterlabs.pacemaker.SendFailed",
174 "Could not queue DBus '%s' request", method);
179 dbus_connection_flush(connection);
183 dbus_pending_call_block(pending);
186 reply = dbus_pending_call_steal_reply(pending);
193 dbus_pending_call_unref(pending);
201 void(*done)(DBusPendingCall *pending,
void *user_data),
202 void *user_data,
int timeout)
204 const char *method = NULL;
205 DBusPendingCall* pending = NULL;
208 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
209 method = dbus_message_get_member (msg);
218 if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
219 crm_err(
"Send with reply failed for %s", method);
222 }
else if (pending == NULL) {
223 crm_err(
"No pending call found for %s: Connection to System DBus may be closed", method);
228 if (dbus_pending_call_get_completed(pending)) {
229 crm_info(
"DBus %s call completed too soon", method);
233 done(pending, user_data);
236 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
241 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
248 const char *
function,
int line)
251 DBusMessageIter lfield;
254 if(dbus_message_iter_init(msg, &lfield)) {
261 "Empty parameter list in reply expecting '%c'", expected);
265 dtype = dbus_message_iter_get_arg_type(field);
267 if(dtype != expected) {
268 DBusMessageIter args;
271 dbus_message_iter_init(msg, &args);
272 sig = dbus_message_iter_get_signature(&args);
274 "Unexpected DBus type, expected %c in '%s' instead of %c",
275 expected, sig, dtype);
284 pcmk_dbus_lookup_result(DBusMessage *reply,
struct db_getall_data *
data)
288 DBusMessageIter dict;
289 DBusMessageIter args;
292 crm_err(
"Cannot get properties from %s for %s: %s",
293 data->target, data->object, error.message);
294 dbus_error_free(&error);
298 dbus_message_iter_init(reply, &args);
300 crm_err(
"Invalid reply from %s for %s", data->target, data->object);
304 dbus_message_iter_recurse(&args, &dict);
305 while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
309 DBusBasicValue value;
312 dbus_message_iter_next (&dict);
316 dbus_message_iter_recurse(&dict, &sv);
317 while (dbus_message_iter_get_arg_type (&sv) != DBUS_TYPE_INVALID) {
318 int dtype = dbus_message_iter_get_arg_type(&sv);
321 case DBUS_TYPE_STRING:
322 dbus_message_iter_get_basic(&sv, &name);
324 if(data->name && strcmp(name.str, data->name) != 0) {
325 dbus_message_iter_next (&sv);
328 case DBUS_TYPE_VARIANT:
329 dbus_message_iter_recurse(&sv, &v);
331 dbus_message_iter_get_basic(&v, &value);
333 crm_trace(
"Property %s[%s] is '%s'", data->object, name.str, value.str);
335 data->callback(name.str, value.str, data->userdata);
339 output = strdup(value.str);
350 dbus_message_iter_next (&sv);
353 dbus_message_iter_next (&dict);
356 if(data->name && data->callback) {
357 crm_trace(
"No value for property %s[%s]", data->object, data->name);
358 data->callback(data->name, NULL, data->userdata);
371 pcmk_dbus_lookup_cb(DBusPendingCall *pending,
void *user_data)
373 DBusMessage *reply = NULL;
377 reply = dbus_pending_call_steal_reply(pending);
380 value = pcmk_dbus_lookup_result(reply, user_data);
384 dbus_message_unref(reply);
390 const char *obj,
const gchar * iface,
const char *name,
391 void (*callback)(
const char *name,
const char *value,
void *userdata),
392 void *userdata, DBusPendingCall **pending,
int timeout)
395 const char *method =
"GetAll";
397 struct db_getall_data *query_data = NULL;
399 crm_debug(
"Calling: %s on %s", method, target);
400 msg = dbus_message_new_method_call(target,
405 crm_err(
"Call to %s failed: No message", method);
409 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
411 query_data = malloc(
sizeof(
struct db_getall_data));
412 if(query_data == NULL) {
413 crm_err(
"Call to %s failed: malloc failed", method);
417 query_data->target = strdup(target);
418 query_data->object = strdup(obj);
419 query_data->callback = callback;
420 query_data->userdata = userdata;
421 query_data->name = NULL;
424 query_data->name = strdup(name);
427 if(query_data->callback) {
428 DBusPendingCall* _pending;
429 _pending =
pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data, timeout);
430 if (pending != NULL) {
437 output = pcmk_dbus_lookup_result(reply, query_data);
440 dbus_message_unref(reply);
444 dbus_message_unref(msg);
450 pcmk_dbus_connection_dispatch_status(DBusConnection *connection,
451 DBusDispatchStatus new_status,
void *data)
453 crm_trace(
"New status %d for connection %p", new_status, connection);
454 if (new_status == DBUS_DISPATCH_DATA_REMAINS){
455 conn_dispatches = g_list_prepend(conn_dispatches, connection);
460 pcmk_dbus_connections_dispatch()
464 for (gIter = conn_dispatches; gIter != NULL; gIter = gIter->next) {
465 DBusConnection *connection = gIter->data;
467 while (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS) {
468 crm_trace(
"Dispatching for connection %p", connection);
469 dbus_connection_dispatch(connection);
473 g_list_free(conn_dispatches);
474 conn_dispatches = NULL;
480 dbus_watch_flags_to_string(
int flags)
482 const char *watch_type;
484 if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE)) {
485 watch_type =
"readwrite";
486 }
else if (flags & DBUS_WATCH_READABLE) {
488 }
else if (flags & DBUS_WATCH_WRITABLE) {
489 watch_type =
"write";
491 watch_type =
"not read or write";
497 pcmk_dbus_watch_dispatch(gpointer userdata)
500 DBusWatch *watch = userdata;
501 int flags = dbus_watch_get_flags(watch);
502 bool enabled = dbus_watch_get_enabled (watch);
505 crm_trace(
"Dispatching client %p: %s", client, dbus_watch_flags_to_string(flags));
506 if (enabled && (flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) {
507 oom = !dbus_watch_handle(watch, flags);
510 oom = !dbus_watch_handle(watch, DBUS_WATCH_ERROR);
513 if(flags != dbus_watch_get_flags(watch)) {
514 flags = dbus_watch_get_flags(watch);
515 crm_trace(
"Dispatched client %p: %s (%d)", client,
516 dbus_watch_flags_to_string(flags), flags);
520 crm_err(
"DBus encountered OOM while attempting to dispatch %p (%s)",
521 client, dbus_watch_flags_to_string(flags));
524 pcmk_dbus_connections_dispatch();
531 pcmk_dbus_watch_destroy(gpointer userdata)
539 .
dispatch = pcmk_dbus_watch_dispatch,
540 .destroy = pcmk_dbus_watch_destroy,
544 pcmk_dbus_watch_add(DBusWatch *watch,
void *data)
546 int fd = dbus_watch_get_unix_fd(watch);
549 "dbus", G_PRIORITY_DEFAULT, fd, watch, &pcmk_dbus_cb);
551 crm_trace(
"Added watch %p with fd=%d to client %p", watch, fd, client);
552 dbus_watch_set_data(watch, client, NULL);
557 pcmk_dbus_watch_toggle(DBusWatch *watch,
void *data)
561 client, (dbus_watch_get_enabled(watch)?
"enabled" :
"disabled"));
566 pcmk_dbus_watch_remove(DBusWatch *watch,
void *data)
570 crm_trace(
"Removed client %p (%p)", client, data);
575 pcmk_dbus_timeout_dispatch(gpointer data)
577 crm_info(
"Timeout %p expired", data);
578 dbus_timeout_handle(data);
583 pcmk_dbus_timeout_add(DBusTimeout *timeout,
void *data)
585 guint
id = g_timeout_add(dbus_timeout_get_interval(timeout),
586 pcmk_dbus_timeout_dispatch, timeout);
588 crm_trace(
"Adding timeout %p (%d)", timeout, dbus_timeout_get_interval(timeout));
591 dbus_timeout_set_data(timeout, GUINT_TO_POINTER(
id), NULL);
597 pcmk_dbus_timeout_remove(DBusTimeout *timeout,
void *data)
599 void *vid = dbus_timeout_get_data(timeout);
600 guint
id = GPOINTER_TO_UINT(vid);
602 crm_trace(
"Removing timeout %p (%p)", timeout, data);
606 dbus_timeout_set_data(timeout, 0, NULL);
611 pcmk_dbus_timeout_toggle(DBusTimeout *timeout,
void *data)
613 bool enabled = dbus_timeout_get_enabled(timeout);
615 crm_trace(
"Toggling timeout for %p to %s", timeout, enabled?
"off":
"on");
618 pcmk_dbus_timeout_add(timeout, data);
620 pcmk_dbus_timeout_remove(timeout, data);
629 dbus_connection_set_exit_on_disconnect(c, FALSE);
630 dbus_connection_set_timeout_functions(c, pcmk_dbus_timeout_add,
631 pcmk_dbus_timeout_remove,
632 pcmk_dbus_timeout_toggle, NULL, NULL);
633 dbus_connection_set_watch_functions(c, pcmk_dbus_watch_add,
634 pcmk_dbus_watch_remove,
635 pcmk_dbus_watch_toggle, NULL, NULL);
636 dbus_connection_set_dispatch_status_function(c, pcmk_dbus_connection_dispatch_status, NULL, NULL);
637 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