summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert McQueen <robot101@debian.org>2005-11-15 17:19:19 +0000
committerRobert McQueen <robot101@debian.org>2005-11-15 17:19:19 +0000
commitb5e4d26adec0a9ec37a1bae7aeb5a68344b78ebf (patch)
tree66eb4e5670d802aee918f8bd3c4674482de0990c
parentd4595960e9edc679cb2656d3ff59d2f899b0f16b (diff)
2005-11-15 Robert McQueen <robot101@debian.org>
* bus/driver.c, bus/services.c, bus/services.h: Add a ReleaseName method to org.freedesktop.DBus to release a bus name or give up waiting in the queue for it. * dbus/dbus-bus.c, dbus/dbus-bus.h, dbus/dbus-shared.h: Add a dbus_bus_release_name method to send the ReleaseName method calls. Add constants for the return values to dbus/dbus-shared.h. * doc/dbus-specification.xml: Document the new ReleaseName method in the specification. * python/dbus_bindings.pyx: Add a low-level python binding for the release name method. * python/exceptions.py, python/service.py: Make freeing BusName objects release the name. Add a NameExistsException, and fix a bug with creating UnknownMethodException. * test/python/test-client.py: Add tests for freeing BusName objects causing names to be released.
-rw-r--r--ChangeLog23
-rw-r--r--bus/driver.c67
-rw-r--r--bus/services.c64
-rw-r--r--bus/services.h6
-rw-r--r--dbus/dbus-bus.c65
-rw-r--r--dbus/dbus-bus.h3
-rw-r--r--dbus/dbus-shared.h5
-rw-r--r--doc/dbus-specification.xml98
-rw-r--r--python/dbus_bindings.pyx33
-rw-r--r--python/exceptions.py10
-rw-r--r--python/service.py11
-rwxr-xr-xtest/python/test-client.py9
12 files changed, 377 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index ee86d051..39e67833 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,28 @@
2005-11-15 Robert McQueen <robot101@debian.org>
+ * bus/driver.c, bus/services.c, bus/services.h: Add a ReleaseName
+ method to org.freedesktop.DBus to release a bus name or give up
+ waiting in the queue for it.
+
+ * dbus/dbus-bus.c, dbus/dbus-bus.h, dbus/dbus-shared.h: Add a
+ dbus_bus_release_name method to send the ReleaseName method calls.
+ Add constants for the return values to dbus/dbus-shared.h.
+
+ * doc/dbus-specification.xml: Document the new ReleaseName method
+ in the specification.
+
+ * python/dbus_bindings.pyx: Add a low-level python binding for the
+ release name method.
+
+ * python/exceptions.py, python/service.py: Make freeing BusName
+ objects release the name. Add a NameExistsException, and fix a
+ bug with creating UnknownMethodException.
+
+ * test/python/test-client.py: Add tests for freeing BusName
+ objects causing names to be released.
+
+2005-11-14 Robert McQueen <robot101@debian.org>
+
* python/service.py: Include the traceback in the error reply when we
send an exception over the bus. _BEST_ _PATCH_ _EVER_
diff --git a/bus/driver.c b/bus/driver.c
index a6c4faff..bc63e7c2 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -470,7 +470,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
DBusMessage *reply;
DBusString service_name;
const char *name;
- int service_reply;
+ dbus_uint32_t service_reply;
dbus_uint32_t flags;
dbus_bool_t retval;
BusRegistry *registry;
@@ -526,6 +526,67 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
}
static dbus_bool_t
+bus_driver_handle_release_service (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusMessage *reply;
+ DBusString service_name;
+ const char *name;
+ dbus_uint32_t service_reply;
+ dbus_bool_t retval;
+ BusRegistry *registry;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ registry = bus_connection_get_registry (connection);
+
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ return FALSE;
+
+ _dbus_verbose ("Trying to release name %s\n", name);
+
+ retval = FALSE;
+ reply = NULL;
+
+ _dbus_string_init_const (&service_name, name);
+
+ if (!bus_registry_release_service (registry, connection,
+ &service_name, &service_reply,
+ transaction, error))
+ goto out;
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID))
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ retval = TRUE;
+
+ out:
+ if (reply)
+ dbus_message_unref (reply);
+ return retval;
+}
+
+static dbus_bool_t
bus_driver_handle_service_exists (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
@@ -1142,6 +1203,10 @@ struct
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
bus_driver_handle_acquire_service },
+ { "ReleaseName",
+ DBUS_TYPE_STRING_AS_STRING,
+ DBUS_TYPE_UINT32_AS_STRING,
+ bus_driver_handle_release_service },
{ "StartServiceByName",
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
diff --git a/bus/services.c b/bus/services.c
index 7a22dce7..87feab2f 100644
--- a/bus/services.c
+++ b/bus/services.c
@@ -434,6 +434,70 @@ bus_registry_acquire_service (BusRegistry *registry,
}
dbus_bool_t
+bus_registry_release_service (BusRegistry *registry,
+ DBusConnection *connection,
+ const DBusString *service_name,
+ dbus_uint32_t *result,
+ BusTransaction *transaction,
+ DBusError *error)
+{
+ dbus_bool_t retval;
+ BusService *service;
+
+ retval = FALSE;
+
+ if (!_dbus_validate_bus_name (service_name, 0,
+ _dbus_string_get_length (service_name)))
+ {
+ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid",
+ _dbus_string_get_const_data (service_name));
+
+ _dbus_verbose ("Attempt to release invalid service name\n");
+
+ goto out;
+ }
+
+ if (_dbus_string_get_byte (service_name, 0) == ':')
+ {
+ /* Not allowed; the base service name cannot be created or released */
+ dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+ "Cannot release a service starting with ':' such as \"%s\"",
+ _dbus_string_get_const_data (service_name));
+
+ _dbus_verbose ("Attempt to release invalid base service name \"%s\"",
+ _dbus_string_get_const_data (service_name));
+
+ goto out;
+ }
+
+ service = bus_registry_lookup (registry, service_name);
+
+ if (service == NULL)
+ {
+ *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT;
+ }
+ else if (!bus_service_has_owner (service, connection))
+ {
+ *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER;
+ }
+ else
+ {
+ if (!bus_service_remove_owner (service, connection,
+ transaction, error))
+ goto out;
+
+ _dbus_assert (!bus_service_has_owner (service, connection));
+ *result = DBUS_RELEASE_NAME_REPLY_RELEASED;
+ }
+
+ retval = TRUE;
+
+ out:
+ return retval;
+}
+
+dbus_bool_t
bus_registry_set_service_context_table (BusRegistry *registry,
DBusHashTable *table)
{
diff --git a/bus/services.h b/bus/services.h
index f0754043..d4b3d833 100644
--- a/bus/services.h
+++ b/bus/services.h
@@ -56,6 +56,12 @@ dbus_bool_t bus_registry_acquire_service (BusRegistry *registry
dbus_uint32_t *result,
BusTransaction *transaction,
DBusError *error);
+dbus_bool_t bus_registry_release_service (BusRegistry *registry,
+ DBusConnection *connection,
+ const DBusString *service_name,
+ dbus_uint32_t *result,
+ BusTransaction *transaction,
+ DBusError *error);
dbus_bool_t bus_registry_set_service_context_table (BusRegistry *registry,
DBusHashTable *table);
diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c
index 107fde90..9016f1b1 100644
--- a/dbus/dbus-bus.c
+++ b/dbus/dbus-bus.c
@@ -777,6 +777,71 @@ dbus_bus_request_name (DBusConnection *connection,
return result;
}
+int
+dbus_bus_release_name (DBusConnection *connection,
+ const char *name,
+ DBusError *error)
+{
+ DBusMessage *message, *reply;
+ dbus_uint32_t result;
+
+ _dbus_return_val_if_fail (connection != NULL, 0);
+ _dbus_return_val_if_fail (name != NULL, 0);
+ _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0);
+ _dbus_return_val_if_error_is_set (error, 0);
+
+ message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "ReleaseName");
+
+ if (message == NULL)
+ {
+ _DBUS_SET_OOM (error);
+ return -1;
+ }
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (message);
+ _DBUS_SET_OOM (error);
+ return -1;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
+ error);
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ return -1;
+ }
+
+ if (dbus_set_error_from_message (error, reply))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return -1;
+ }
+
+ if (!dbus_message_get_args (reply, error,
+ DBUS_TYPE_UINT32, &result,
+ DBUS_TYPE_INVALID))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return -1;
+ }
+
+ dbus_message_unref (reply);
+
+ return result;
+}
+
/**
* Checks whether a certain name has an owner.
*
diff --git a/dbus/dbus-bus.h b/dbus/dbus-bus.h
index 24470672..2329e138 100644
--- a/dbus/dbus-bus.h
+++ b/dbus/dbus-bus.h
@@ -48,6 +48,9 @@ int dbus_bus_request_name (DBusConnection *connection,
const char *name,
unsigned int flags,
DBusError *error);
+int dbus_bus_release_name (DBusConnection *connection,
+ const char *name,
+ DBusError *error);
dbus_bool_t dbus_bus_name_has_owner (DBusConnection *connection,
const char *name,
DBusError *error);
diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h
index a1f49a02..a8519c13 100644
--- a/dbus/dbus-shared.h
+++ b/dbus/dbus-shared.h
@@ -77,6 +77,11 @@ typedef enum
#define DBUS_REQUEST_NAME_REPLY_EXISTS 3
#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
+/* Replies to releasing a name */
+#define DBUS_RELEASE_NAME_REPLY_RELEASED 1
+#define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2
+#define DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3
+
/* Replies to service starts */
#define DBUS_START_REPLY_SUCCESS 1
#define DBUS_START_REPLY_ALREADY_RUNNING 2
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index a30e1013..d1184650 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -2567,7 +2567,8 @@
A connection can request additional names to be associated with it using
the <literal>org.freedesktop.DBus.RequestName</literal> message. <xref
linkend="message-protocol-names-bus"/> describes the format of a valid
- name.
+ name. These names can be released again using the
+ <literal>org.freedesktop.DBus.ReleaseName</literal> message.
</para>
<sect3 id="bus-messages-request-name">
@@ -2700,6 +2701,101 @@
</tgroup>
</informaltable>
</para>
+ </sect3>
+
+ <sect3 id="bus-messages-release-name">
+ <title><literal>org.freedesktop.DBus.ReleaseName</literal></title>
+ <para>
+ As a method:
+ <programlisting>
+ UINT32 ReleaseName (in STRING name)
+ </programlisting>
+ Message arguments:
+ <informaltable>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Argument</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>0</entry>
+ <entry>STRING</entry>
+ <entry>Name to release</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ Reply arguments:
+ <informaltable>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Argument</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>0</entry>
+ <entry>UINT32</entry>
+ <entry>Return value</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ <para>
+ This method call should be sent to
+ <literal>org.freedesktop.DBus</literal> and asks the message bus to
+ release the method caller's claim to the given name. If the caller is
+ the primary owner, a new primary owner will be selected from the
+ queue if any other owners are waiting. If the caller is waiting in
+ the queue for the name, the caller will removed from the queue and
+ will not be made an owner of the name if it later becomes available.
+ If there are no other owners in the queue for the name, it will be
+ removed from the bus entirely.
+
+ The return code can be one of the following values:
+
+ <informaltable>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Conventional Name</entry>
+ <entry>Value</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>DBUS_RELEASE_NAME_REPLY_RELEASED</entry>
+ <entry>1</entry> <entry>The caller has released his claim on
+ the given name. Either the caller was the primary owner of
+ the name, and the name is now unused or taken by somebody
+ waiting in the queue for the name, or the caller was waiting
+ in the queue for the name and has now been removed from the
+ queue.</entry>
+ </row>
+ <row>
+ <entry>DBUS_RELEASE_NAME_REPLY_NON_EXISTENT</entry>
+ <entry>2</entry>
+ <entry>The given name does not exist on this bus.</entry>
+ </row>
+ <row>
+ <entry>DBUS_RELEASE_NAME_REPLY_NOT_OWNER</entry>
+ <entry>3</entry>
+ <entry>The caller was not the primary owner of this name,
+ and was also not waiting in the queue to own this name.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
</sect3>
</sect2>
diff --git a/python/dbus_bindings.pyx b/python/dbus_bindings.pyx
index 75e448ee..8b1b221b 100644
--- a/python/dbus_bindings.pyx
+++ b/python/dbus_bindings.pyx
@@ -1710,10 +1710,10 @@ def bus_get_unix_user(Connection connection, service_name):
return retval
-#These are defines, not enums so they aren't auto generated
-DBUS_START_REPLY_SUCCESS = 0
-DBUS_START_REPLY_ALREADY_RUNNING = 1
-
+# these are defines, not enums, so they aren't auto generated
+DBUS_START_REPLY_SUCCESS = 0
+DBUS_START_REPLY_ALREADY_RUNNING = 1
+
def bus_start_service_by_name(Connection connection, service_name, flags=0):
cdef DBusError error
dbus_error_init(&error)
@@ -1771,9 +1771,30 @@ def bus_request_name(Connection connection, service_name, flags=0):
errormsg = error.message
dbus_error_free(&error)
raise DBusException, errormsg
-
+
return retval
-
+
+RELEASE_NAME_REPLY_RELEASED = 1
+RELEASE_NAME_REPLY_NON_EXISTENT = 2
+RELEASE_NAME_REPLY_NOT_OWNER = 3
+
+def bus_release_name(Connection connection, service_name):
+ cdef DBusError error
+ dbus_error_init(&error)
+ cdef int retval
+ cdef DBusConnection *conn
+
+ conn = connection._get_conn()
+ retval = dbus_bus_release_name(conn,
+ service_name,
+ &error)
+ if dbus_error_is_set(&error):
+ errormsg = error.message
+ dbus_error_free(&error)
+ raise DBusException, errormsg
+
+ return retval
+
def bus_name_has_owner(Connection connection, service_name):
cdef DBusError error
dbus_error_init(&error)
diff --git a/python/exceptions.py b/python/exceptions.py
index 5cb8d5a3..2b01b96e 100644
--- a/python/exceptions.py
+++ b/python/exceptions.py
@@ -17,9 +17,13 @@ class ValidationException(DBusException):
class IntrospectionParserException(DBusException):
def __init__(self, msg=''):
- DBusException.__init__(self, "Error parsing introspect data: %s"%msg)
+ DBusException.__init__(self, "Error parsing introspect data: %s"%msg)
class UnknownMethodException(DBusException):
- def __init__(self, msg=''):
- DBusException.__init__("Unknown method: %s"%msg)
+ def __init__(self, method):
+ DBusException.__init__(self, "Unknown method: %s"%method)
+
+class NameExistsException(DBusException):
+ def __init__(self, name):
+ DBusException.__init__(self, "Bus name already exists: %s"%name)
diff --git a/python/service.py b/python/service.py
index 6c3561ad..e5a7002b 100644
--- a/python/service.py
+++ b/python/service.py
@@ -1,9 +1,9 @@
-
-import dbus_bindings
+import dbus_bindings
import _dbus
import operator
import traceback
+from exceptions import NameExistsException
from exceptions import UnknownMethodException
from decorators import method
from decorators import signal
@@ -31,13 +31,13 @@ class BusName(object):
# because you can't put flags in, but... who knows?
pass
elif retval == dbus_bindings.REQUEST_NAME_REPLY_EXISTS:
- raise dbus_bindings.DBusException('requested name %s already exists' % name)
+ raise NameExistsException(name)
elif retval == dbus_bindings.REQUEST_NAME_REPLY_ALREADY_OWNER:
# if this is a shared bus which is being used by someone
# else in this process, this can happen legitimately
pass
else:
- raise dbus_bindings.DBusException('requesting name %s returned unexpected value %s' % (name, retval))
+ raise RuntimeError('requesting bus name %s returned unexpected value %s' % (name, retval))
# and create the object
bus_name = object.__new__(cls)
@@ -57,8 +57,7 @@ class BusName(object):
# we can delete the low-level name here because these objects
# are guaranteed to exist only once for each bus name
def __del__(self):
- # FIXME: we don't have this function yet :)
- #dbus_bindings.bus_release_name(self._bus.get_connection(), self._named_service)
+ dbus_bindings.bus_release_name(self._bus.get_connection(), self._name)
pass
def get_bus(self):
diff --git a/test/python/test-client.py b/test/python/test-client.py
index ab703502..e972f446 100755
--- a/test/python/test-client.py
+++ b/test/python/test-client.py
@@ -252,8 +252,17 @@ class TestDBusBindings(unittest.TestCase):
else:
names[name] = busname
+ del busname
+
print
+ del names
+
+ bus = dbus.Bus()
+ ret = dbus.dbus_bindings.bus_name_has_owner(bus._connection, 'org.freedesktop.DBus.Python.TestName')
+ self.assert_(not ret, 'deleting reference failed to release BusName org.freedesktop.DBus.Python.TestName')
+
+
class TestDBusPythonToGLibBindings(unittest.TestCase):
def setUp(self):
self.bus = dbus.SessionBus()