diff options
| -rw-r--r-- | ChangeLog | 23 | ||||
| -rw-r--r-- | bus/driver.c | 67 | ||||
| -rw-r--r-- | bus/services.c | 64 | ||||
| -rw-r--r-- | bus/services.h | 6 | ||||
| -rw-r--r-- | dbus/dbus-bus.c | 65 | ||||
| -rw-r--r-- | dbus/dbus-bus.h | 3 | ||||
| -rw-r--r-- | dbus/dbus-shared.h | 5 | ||||
| -rw-r--r-- | doc/dbus-specification.xml | 98 | ||||
| -rw-r--r-- | python/dbus_bindings.pyx | 33 | ||||
| -rw-r--r-- | python/exceptions.py | 10 | ||||
| -rw-r--r-- | python/service.py | 11 | ||||
| -rwxr-xr-x | test/python/test-client.py | 9 | 
12 files changed, 377 insertions, 17 deletions
@@ -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()  | 
