7 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties" 15 void (*callback)(
const char *name,
const char *value,
void *userdata);
18 static bool pcmk_dbus_error_check(DBusError *err,
const char *prefix,
const char *
function,
int line)
20 if (err && dbus_error_is_set(err)) {
21 do_crm_log_alias(LOG_ERR, __FILE__,
function, line,
"%s: DBus error '%s'", prefix, err->message);
31 DBusConnection *connection;
33 dbus_error_init(&err);
34 connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
35 if(pcmk_dbus_error_check(&err,
"Could not connect to System DBus", __FUNCTION__, __LINE__)) {
54 dbus_error_init(&error);
57 error.name =
"org.clusterlabs.pacemaker.NoRequest";
58 error.message =
"No request sent";
60 }
else if(reply == NULL) {
61 error.name =
"org.clusterlabs.pacemaker.NoReply";
62 error.message =
"No reply";
66 int dtype = dbus_message_get_type(reply);
70 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
71 dbus_message_iter_init(reply, &args);
72 sig = dbus_message_iter_get_signature(&args);
73 crm_trace(
"Call to %s returned '%s'", method, sig);
76 case DBUS_MESSAGE_TYPE_INVALID:
77 error.message =
"Invalid reply";
78 error.name =
"org.clusterlabs.pacemaker.InvalidReply";
79 crm_err(
"Error processing %s response: %s", method, error.message);
81 case DBUS_MESSAGE_TYPE_METHOD_CALL:
82 error.message =
"Invalid reply (method call)";
83 error.name =
"org.clusterlabs.pacemaker.InvalidReply.Method";
84 crm_err(
"Error processing %s response: %s", method, error.message);
86 case DBUS_MESSAGE_TYPE_SIGNAL:
87 error.message =
"Invalid reply (signal)";
88 error.name =
"org.clusterlabs.pacemaker.InvalidReply.Signal";
89 crm_err(
"Error processing %s response: %s", method, error.message);
92 case DBUS_MESSAGE_TYPE_ERROR:
93 dbus_set_error_from_message (&error, reply);
94 crm_info(
"%s error '%s': %s", method, error.name, error.message);
97 error.message =
"Unknown reply type";
98 error.name =
"org.clusterlabs.pacemaker.InvalidReply.Type";
99 crm_err(
"Error processing %s response: %s (%d)", method, error.message, dtype);
103 if(error.name || error.message) {
113 DBusMessage *
pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error,
int timeout)
115 const char *method = NULL;
116 DBusMessage *reply = NULL;
117 DBusPendingCall* pending = NULL;
119 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
120 method = dbus_message_get_member (msg);
127 if (!dbus_connection_send_with_reply (connection, msg, &pending, timeout)) {
129 dbus_error_init(error);
130 error->message =
"Call to dbus_connection_send_with_reply() failed";
131 error->name =
"org.clusterlabs.pacemaker.SendFailed";
133 crm_err(
"Error sending %s request", method);
137 dbus_connection_flush(connection);
141 dbus_pending_call_block(pending);
144 reply = dbus_pending_call_steal_reply(pending);
151 dbus_pending_call_unref(pending);
158 void(*done)(DBusPendingCall *pending,
void *user_data),
void *user_data,
int timeout)
161 const char *method = NULL;
162 DBusPendingCall* pending = NULL;
164 dbus_error_init(&error);
167 CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
168 method = dbus_message_get_member (msg);
176 if (!dbus_connection_send_with_reply (connection, msg, &pending, timeout)) {
177 crm_err(
"Send with reply failed for %s", method);
180 }
else if (pending == NULL) {
181 crm_err(
"No pending call found for %s: Connection to System DBus may be closed", method);
186 if (dbus_pending_call_get_completed(pending)) {
187 crm_info(
"DBus %s call completed too soon", method);
191 done(pending, user_data);
194 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
199 CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
204 bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field,
int expected,
const char *
function,
int line)
207 DBusMessageIter lfield;
210 if(dbus_message_iter_init(msg, &lfield)) {
217 "Empty parameter list in reply expecting '%c'", expected);
221 dtype = dbus_message_iter_get_arg_type(field);
223 if(dtype != expected) {
224 DBusMessageIter args;
227 dbus_message_iter_init(msg, &args);
228 sig = dbus_message_iter_get_signature(&args);
230 "Unexpected DBus type, expected %c in '%s' instead of %c",
231 expected, sig, dtype);
240 pcmk_dbus_lookup_result(DBusMessage *reply,
struct db_getall_data *
data)
244 DBusMessageIter dict;
245 DBusMessageIter args;
248 crm_err(
"Cannot get properties from %s for %s", data->target, data->object);
252 dbus_message_iter_init(reply, &args);
254 crm_err(
"Invalid reply from %s for %s", data->target, data->object);
258 dbus_message_iter_recurse(&args, &dict);
259 while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
263 DBusBasicValue value;
266 dbus_message_iter_next (&dict);
270 dbus_message_iter_recurse(&dict, &sv);
271 while (dbus_message_iter_get_arg_type (&sv) != DBUS_TYPE_INVALID) {
272 int dtype = dbus_message_iter_get_arg_type(&sv);
275 case DBUS_TYPE_STRING:
276 dbus_message_iter_get_basic(&sv, &name);
278 if(data->name && strcmp(name.str, data->name) != 0) {
279 dbus_message_iter_next (&sv);
282 case DBUS_TYPE_VARIANT:
283 dbus_message_iter_recurse(&sv, &v);
285 dbus_message_iter_get_basic(&v, &value);
287 crm_trace(
"Property %s[%s] is '%s'", data->object, name.str, value.str);
289 data->callback(name.str, value.str, data->userdata);
293 output = strdup(value.str);
304 dbus_message_iter_next (&sv);
307 dbus_message_iter_next (&dict);
310 if(data->name && data->callback) {
311 crm_trace(
"No value for property %s[%s]", data->object, data->name);
312 data->callback(data->name, NULL, data->userdata);
325 pcmk_dbus_lookup_cb(DBusPendingCall *pending,
void *user_data)
327 DBusMessage *reply = NULL;
331 reply = dbus_pending_call_steal_reply(pending);
334 value = pcmk_dbus_lookup_result(reply, user_data);
338 dbus_message_unref(reply);
344 DBusConnection *connection,
const char *target,
const char *obj,
const gchar * iface,
const char *name,
345 void (*callback)(
const char *name,
const char *value,
void *userdata),
void *userdata, DBusPendingCall **pending,
349 const char *method =
"GetAll";
352 struct db_getall_data *query_data = NULL;
356 crm_debug(
"Calling: %s on %s", method, target);
357 msg = dbus_message_new_method_call(target,
363 crm_err(
"Call to %s failed: No message", method);
367 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
369 query_data = malloc(
sizeof(
struct db_getall_data));
370 if(query_data == NULL) {
371 crm_err(
"Call to %s failed: malloc failed", method);
375 query_data->target = strdup(target);
376 query_data->object = strdup(obj);
377 query_data->callback = callback;
378 query_data->userdata = userdata;
379 query_data->name = NULL;
382 query_data->name = strdup(name);
385 if(query_data->callback) {
386 DBusPendingCall* _pending;
387 _pending =
pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data, timeout);
388 if (pending != NULL) {
395 output = pcmk_dbus_lookup_result(reply, query_data);
398 dbus_message_unref(reply);
402 dbus_message_unref(msg);
407 static void pcmk_dbus_connection_dispatch(DBusConnection *connection, DBusDispatchStatus new_status,
void *data){
408 crm_trace(
"status %d for %p", new_status, data);
409 if (new_status == DBUS_DISPATCH_DATA_REMAINS){
410 dbus_connection_dispatch(connection);
412 while (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS) {
413 dbus_connection_dispatch(connection);
421 dbus_watch_flags_to_string (
int flags)
423 const char *watch_type;
425 if ((flags & DBUS_WATCH_READABLE) &&
426 (flags & DBUS_WATCH_WRITABLE))
427 watch_type =
"readwrite";
428 else if (flags & DBUS_WATCH_READABLE)
430 else if (flags & DBUS_WATCH_WRITABLE)
431 watch_type =
"write";
433 watch_type =
"not read or write";
438 pcmk_dbus_watch_dispatch(gpointer userdata)
441 DBusWatch *watch = userdata;
442 int flags = dbus_watch_get_flags(watch);
443 bool enabled = dbus_watch_get_enabled (watch);
446 crm_trace(
"Dispatching client %p: %s", client, dbus_watch_flags_to_string(flags));
447 if (enabled && is_set(flags, DBUS_WATCH_READABLE)) {
448 oom = !dbus_watch_handle(watch, flags);
450 }
else if (enabled && is_set(flags, DBUS_WATCH_READABLE)) {
451 oom = !dbus_watch_handle(watch, flags);
454 oom = !dbus_watch_handle(watch, DBUS_WATCH_ERROR);
457 if(flags != dbus_watch_get_flags(watch)) {
458 flags = dbus_watch_get_flags(watch);
459 crm_trace(
"Dispatched client %p: %s (%d)", client, dbus_watch_flags_to_string(flags), flags);
463 crm_err(
"DBus encountered OOM while attempting to dispatch %p (%s)", client, dbus_watch_flags_to_string(flags));
469 pcmk_dbus_watch_destroy(gpointer userdata)
477 .
dispatch = pcmk_dbus_watch_dispatch,
478 .destroy = pcmk_dbus_watch_destroy,
482 pcmk_dbus_watch_add(DBusWatch *watch,
void *data){
483 int fd = dbus_watch_get_unix_fd(watch);
486 "dbus", G_PRIORITY_DEFAULT, fd, watch, &pcmk_dbus_cb);
488 crm_trace(
"Added watch %p with fd=%d to client %p", watch, fd, client);
489 dbus_watch_set_data(watch, client, NULL);
494 pcmk_dbus_watch_toggle(DBusWatch *watch,
void *data)
497 crm_notice(
"DBus client %p is now %s", client, dbus_watch_get_enabled(watch)?
"enabled":
"disabled");
502 pcmk_dbus_watch_remove(DBusWatch *watch,
void *data){
505 crm_trace(
"Removed client %p (%p)", client, data);
510 pcmk_dbus_timeout_dispatch(gpointer data)
512 crm_info(
"Timeout %p expired", data);
513 dbus_timeout_handle(data);
518 pcmk_dbus_timeout_add(DBusTimeout *timeout,
void *data){
519 guint
id = g_timeout_add(dbus_timeout_get_interval(timeout), pcmk_dbus_timeout_dispatch, timeout);
521 crm_trace(
"Adding timeout %p (%d)", timeout, dbus_timeout_get_interval(timeout));
524 dbus_timeout_set_data(timeout, GUINT_TO_POINTER(
id), NULL);
530 pcmk_dbus_timeout_remove(DBusTimeout *timeout,
void *data){
531 void *vid = dbus_timeout_get_data(timeout);
532 guint
id = GPOINTER_TO_UINT(vid);
534 crm_trace(
"Removing timeout %p (%p)", timeout, data);
538 dbus_timeout_set_data(timeout, 0, NULL);
543 pcmk_dbus_timeout_toggle(DBusTimeout *timeout,
void *data){
544 bool enabled = dbus_timeout_get_enabled(timeout);
546 crm_trace(
"Toggling timeout for %p to %s", timeout, enabled?
"off":
"on");
549 pcmk_dbus_timeout_add(timeout, data);
551 pcmk_dbus_timeout_remove(timeout, data);
558 dbus_connection_set_exit_on_disconnect (c, FALSE);
559 dbus_connection_set_timeout_functions(
560 c, pcmk_dbus_timeout_add, pcmk_dbus_timeout_remove, pcmk_dbus_timeout_toggle, NULL, NULL);
561 dbus_connection_set_watch_functions(c, pcmk_dbus_watch_add, pcmk_dbus_watch_remove, pcmk_dbus_watch_toggle, NULL, NULL);
562 dbus_connection_set_dispatch_status_function(c, pcmk_dbus_connection_dispatch, NULL, NULL);
564 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.
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
bool pcmk_dbus_find_error(const char *method, DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)