bluez5: add convenience helper for dbus pending calls

This commit is contained in:
Pauli Virtanen 2022-11-08 21:58:30 +02:00 committed by Wim Taymans
parent 42e463f726
commit a07dfbbdb9
2 changed files with 104 additions and 35 deletions

View file

@ -292,36 +292,26 @@ static void interfaces_removed(struct impl *impl, DBusMessageIter *arg_iter)
}
}
static void get_managed_objects_reply(DBusPendingCall *pending, void *user_data)
static void get_managed_objects_reply(DBusPendingCall **call_ptr, DBusMessage *r)
{
struct impl *impl = user_data;
DBusMessage *r;
struct impl *impl = SPA_CONTAINER_OF(call_ptr, struct impl, get_managed_objects_call);
DBusMessageIter it[6];
spa_assert(pending == impl->get_managed_objects_call);
impl->get_managed_objects_call = NULL;
r = dbus_pending_call_steal_reply(pending);
dbus_pending_call_unref(pending);
if (r == NULL)
return;
if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
spa_log_warn(impl->log, "BlueZ D-Bus ObjectManager not available");
goto done;
return;
}
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
spa_log_error(impl->log, "GetManagedObjects() failed: %s",
dbus_message_get_error_name(r));
goto done;
return;
}
if (!dbus_message_iter_init(r, &it[0]) ||
!spa_streq(dbus_message_get_signature(r), "a{oa{sa{sv}}}")) {
spa_log_error(impl->log, "Invalid reply signature for GetManagedObjects()");
goto done;
return;
}
/* Add fake object representing the service itself */
@ -338,17 +328,11 @@ static void get_managed_objects_reply(DBusPendingCall *pending, void *user_data)
}
impl->objects_listed = true;
done:
dbus_message_unref(r);
return;
}
static int get_managed_objects(struct impl *impl)
{
DBusMessage *m = NULL;
DBusPendingCall *call;
int res = 0;
DBusMessage *m;
if (impl->objects_listed || impl->get_managed_objects_call)
return 0;
@ -362,19 +346,8 @@ static int get_managed_objects(struct impl *impl)
dbus_message_set_auto_start(m, false);
if (!dbus_connection_send_with_reply(impl->conn, m, &call, -1)) {
res = -EIO;
goto done;
}
dbus_pending_call_set_notify(call, get_managed_objects_reply, impl, NULL);
impl->get_managed_objects_call = call;
done:
if (m)
dbus_message_unref(m);
return res;
return spa_dbus_async_call(impl->conn, m, &impl->get_managed_objects_call,
get_managed_objects_reply);
}
@ -696,3 +669,72 @@ struct spa_list *spa_dbus_monitor_object_list(struct spa_dbus_monitor *this, con
return object_list;
}
typedef void (*pending_call_reply_t)(DBusPendingCall **, DBusMessage *);
static dbus_int32_t async_call_reply_id = -1;
static void async_call_reply(DBusPendingCall *pending, void *user_data)
{
DBusPendingCall **call_ptr = user_data;
DBusMessage *r;
pending_call_reply_t reply;
spa_assert(pending == *call_ptr);
*call_ptr = NULL;
r = dbus_pending_call_steal_reply(pending);
reply = dbus_pending_call_get_data(pending, async_call_reply_id);
dbus_pending_call_unref(pending);
spa_assert(reply != NULL);
if (r == NULL)
return;
reply(call_ptr, r);
dbus_message_unref(r);
}
int spa_dbus_async_call(DBusConnection *conn, DBusMessage *msg,
DBusPendingCall **call_ptr,
pending_call_reply_t reply)
{
int res = -EIO;
DBusPendingCall *pending;
spa_assert(msg);
spa_assert(call_ptr);
if (async_call_reply_id == -1) {
if (!dbus_pending_call_allocate_data_slot(&async_call_reply_id))
goto done;
}
if (*call_ptr) {
res = -EBUSY;
goto done;
}
if (!dbus_connection_send_with_reply(conn, msg, &pending, -1))
goto done;
if (!dbus_pending_call_set_data(pending, async_call_reply_id, reply, NULL)) {
dbus_pending_call_cancel(pending);
dbus_pending_call_unref(pending);
goto done;
}
if (!dbus_pending_call_set_notify(pending, async_call_reply, call_ptr, NULL)) {
dbus_pending_call_cancel(pending);
dbus_pending_call_unref(pending);
goto done;
}
*call_ptr = pending;
res = 0;
done:
dbus_message_unref(msg);
return res;
}

View file

@ -50,6 +50,7 @@ struct spa_dbus_interface {
/**
* Interface at the object path removed.
* No other hooks will be called after this.
* The object will be deallocated after this, so any associated data,
* for example in a custom object struct, can be freed in this hook.
*/
@ -136,4 +137,30 @@ void spa_dbus_monitor_ignore_object(struct spa_dbus_monitor *monitor,
struct spa_list *spa_dbus_monitor_object_list(struct spa_dbus_monitor *monitor,
const char *interface);
/**
* Make an asynchronous DBus call.
*
* On successful return, *call_ptr contains the pending call handle.
* The same address is passed to the reply function, and can be used
* to locate the address container object. The reply function does not
* need to unref the reply, or set *call_ptr to NULL itself.
*
* The msg passed in is stolen, and unref'd also on errors.
*
* \returns 0 on success, < 0 on error.
*/
int spa_dbus_async_call(DBusConnection *conn, DBusMessage *msg,
DBusPendingCall **call_ptr,
void (*reply)(DBusPendingCall **call_ptr, DBusMessage *reply));
/** Convenience for pending call cancel + unref */
static inline void spa_dbus_async_call_cancel(DBusPendingCall **call_ptr)
{
if (*call_ptr) {
dbus_pending_call_cancel(*call_ptr);
dbus_pending_call_unref(*call_ptr);
*call_ptr = NULL;
}
}
#endif