X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/638f9a561e8353ae9bd7e07e4f42e4c4f53f617e..2ff195aaa4238105a6a426e927efb8f81e94b9c5:/src/modules/reserve.c diff --git a/src/modules/reserve.c b/src/modules/reserve.c index 5597f177..f78805ed 100644 --- a/src/modules/reserve.c +++ b/src/modules/reserve.c @@ -291,9 +291,9 @@ static DBusHandlerResult filter_handler( DBusMessage *m, void *userdata) { - DBusMessage *reply; rd_device *d; DBusError error; + char *name_owner = NULL; dbus_error_init(&error); @@ -311,6 +311,21 @@ static DBusHandlerResult filter_handler( goto invalid; if (strcmp(name, d->service_name) == 0 && d->owning) { + /* Verify the actual owner of the name to avoid leaked NameLost + * signals from previous reservations. The D-Bus daemon will send + * all messages asynchronously in the correct order, but we could + * potentially process them too late due to the pseudo-blocking + * call mechanism used during both acquisition and release. This + * can happen if we release the device and immediately after + * reacquire it before NameLost is processed. */ + if (!d->gave_up) { + const char *un; + + if ((un = dbus_bus_get_unique_name(c)) && rd_dbus_get_name_owner(c, d->service_name, &name_owner, &error) == 0) + if (strcmp(name_owner, un) == 0) + goto invalid; /* Name still owned by us */ + } + d->owning = 0; if (!d->gave_up) { @@ -323,35 +338,14 @@ static DBusHandlerResult filter_handler( rd_release(d); } - return DBUS_HANDLER_RESULT_HANDLED; } } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - invalid: - if (!(reply = dbus_message_new_error( - m, - DBUS_ERROR_INVALID_ARGS, - "Invalid arguments"))) - goto oom; - - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - + free(name_owner); dbus_error_free(&error); - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -629,3 +623,59 @@ void* rd_get_userdata(rd_device *d) { return d->userdata; } + +int rd_dbus_get_name_owner( + DBusConnection *connection, + const char *name, + char **name_owner, + DBusError *error) { + + DBusMessage *msg, *reply; + int r; + + *name_owner = NULL; + + if (!(msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner"))) { + r = -ENOMEM; + goto fail; + } + + if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { + r = -ENOMEM; + goto fail; + } + + reply = dbus_connection_send_with_reply_and_block(connection, msg, DBUS_TIMEOUT_USE_DEFAULT, error); + dbus_message_unref(msg); + msg = NULL; + + if (reply) { + if (!dbus_message_get_args(reply, error, DBUS_TYPE_STRING, name_owner, DBUS_TYPE_INVALID)) { + dbus_message_unref(reply); + r = -EIO; + goto fail; + } + + *name_owner = strdup(*name_owner); + dbus_message_unref(reply); + + if (!*name_owner) { + r = -ENOMEM; + goto fail; + } + + } else if (dbus_error_has_name(error, "org.freedesktop.DBus.Error.NameHasNoOwner")) + dbus_error_free(error); + else { + r = -EIO; + goto fail; + } + + return 0; + +fail: + if (msg) + dbus_message_unref(msg); + + return r; +}