]> code.delx.au - pulseaudio/blobdiff - src/modules/reserve.c
bluetooth: Don't mark device valid before it has an adapter
[pulseaudio] / src / modules / reserve.c
index 9a9591d25d3a381b6aa012e8614ca0b52c0b6d05..f78805ed730e6662a51b499667cc132d15b46c16 100644 (file)
@@ -1,3 +1,5 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: t -*-*/
+
 /***
   Copyright 2009 Lennart Poettering
 
@@ -43,16 +45,15 @@ struct rd_device {
 
        DBusConnection *connection;
 
-       int owning:1;
-       int registered:1;
-       int filtering:1;
-       int gave_up:1;
+       unsigned owning:1;
+       unsigned registered:1;
+       unsigned filtering:1;
+       unsigned gave_up:1;
 
        rd_request_cb_t request_cb;
        void *userdata;
 };
 
-
 #define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
 #define OBJECT_PREFIX "/org/freedesktop/ReserveDevice1/"
 
@@ -290,13 +291,14 @@ static DBusHandlerResult filter_handler(
        DBusMessage *m,
        void *userdata) {
 
-       DBusMessage *reply;
        rd_device *d;
        DBusError error;
+       char *name_owner = NULL;
 
        dbus_error_init(&error);
 
        d = userdata;
+       assert(d->ref >= 1);
 
        if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameLost")) {
                const char *name;
@@ -309,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)  {
@@ -321,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);
-
-       dbus_error_free(&error);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
-       if (reply)
-               dbus_message_unref(reply);
-
+       free(name_owner);
        dbus_error_free(&error);
 
-       return DBUS_HANDLER_RESULT_NEED_MEMORY;
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
 
@@ -560,7 +556,7 @@ void rd_release(
 
        assert(d->ref > 0);
 
-       if (--d->ref)
+       if (--d->ref > 0)
                return;
 
 
@@ -575,17 +571,11 @@ void rd_release(
                        d->connection,
                        d->object_path);
 
-       if (d->owning) {
-               DBusError error;
-               dbus_error_init(&error);
-
+       if (d->owning)
                dbus_bus_release_name(
                        d->connection,
                        d->service_name,
-                       &error);
-
-               dbus_error_free(&error);
-       }
+                       NULL);
 
        free(d->device_name);
        free(d->application_name);
@@ -633,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;
+}