blob: fd4f04d187eb518ba06ca2dffc0017d87e1f833d [file] [log] [blame]
/*
* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <stdlib.h>
#include "dbus.h"
#include "util.h"
struct _dbus_t {
DBusConnection *conn;
int terminate;
struct {
DBusObjectPathVTable vtable;
const char* interface;
const char* signal;
const char* rule;
void* user_data;
dbus_message_handler_t signal_handler;
} signal;
};
dbus_t* dbus_init()
{
dbus_t* new_dbus;
DBusError err;
dbus_error_init(&err);
new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
if (dbus_error_is_set(&err)) {
LOG(ERROR, "Cannot get dbus connection");
free(new_dbus);
return NULL;
}
dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
return new_dbus;
}
bool dbus_method_call0(dbus_t* dbus, const char* service_name,
const char* service_path, const char* service_interface,
const char* method)
{
DBusMessage *msg = NULL;
msg = dbus_message_new_method_call(service_name,
service_path, service_interface, method);
if (!msg)
return false;
if (!dbus_connection_send_with_reply_and_block(dbus->conn,
msg, 3000, NULL)) {
dbus_message_unref(msg);
return false;
}
dbus_connection_flush(dbus->conn);
dbus_message_unref(msg);
return true;
}
bool dbus_method_call1(dbus_t* dbus, const char* service_name,
const char* service_path, const char* service_interface,
const char* method, int* param)
{
DBusMessage *msg = NULL;
msg = dbus_message_new_method_call(service_name,
service_path, service_interface, method);
if (!msg)
return false;
if (!dbus_message_append_args(msg,
DBUS_TYPE_INT32, param, DBUS_TYPE_INVALID)) {
dbus_message_unref(msg);
return false;
}
if (!dbus_connection_send_with_reply_and_block(dbus->conn,
msg, 3000, NULL)) {
dbus_message_unref(msg);
return false;
}
dbus_connection_flush(dbus->conn);
dbus_message_unref(msg);
return true;
}
static void
dbus_path_unregister_function(DBusConnection *connection, void *user_data)
{
}
static DBusHandlerResult
dbus_message_function(DBusConnection *connection,
DBusMessage *message, void* user_data)
{
dbus_t* dbus = (dbus_t*)user_data;
if (dbus_message_is_signal(message, dbus->signal.interface,
dbus->signal.signal)) {
dbus->signal.signal_handler(dbus, dbus->signal.user_data);
}
return DBUS_HANDLER_RESULT_HANDLED;
}
bool dbus_signal_match_handler(
dbus_t* dbus,
const char* signal,
const char* path,
const char* interface,
const char* rule,
dbus_message_handler_t handler,
void *user_data)
{
DBusError err;
dbus->signal.vtable.unregister_function = dbus_path_unregister_function;
dbus->signal.vtable.message_function = dbus_message_function;
dbus->signal.signal_handler = handler;
dbus->signal.signal = signal;
dbus->signal.user_data = user_data;
dbus->signal.interface = interface;
if (!dbus_connection_register_object_path(dbus->conn, path,
&dbus->signal.vtable, dbus)) {
LOG(ERROR, "register_object_path failed");
return false;
}
dbus_error_init(&err);
dbus_bus_add_match(dbus->conn, rule, &err);
if (dbus_error_is_set(&err)) {
LOG(ERROR, "add_match failed: %s", err.message);
return false;
}
return true;
}
int dbus_wait_for_messages(dbus_t *dbus, int64_t timeout_ms)
{
int ret = DBUS_STATUS_NOERROR;
int64_t terminate_ms = -1;
if (timeout_ms > 0)
terminate_ms = get_monotonic_time_ms() + timeout_ms;
while (dbus_connection_read_write_dispatch(dbus->conn, -1)) {
if ((terminate_ms > 0) && (get_monotonic_time_ms() > terminate_ms)) {
dbus->terminate = true;
ret = DBUS_STATUS_TIMEOUT;
}
if (dbus->terminate)
break;
}
return ret;
}
void dbus_stop_wait(dbus_t* dbus)
{
dbus->terminate = true;
}
void dbus_destroy(dbus_t* dbus)
{
/* FIXME - not sure what the right counterpart to
dbus_bus_get() is, unref documentation is rather
unclear. Not a big issue but it would be nice to
clean up properly here */
/* dbus_connection_unref(dbus->conn); */
free(dbus);
}