diff options
39 files changed, 1362 insertions, 722 deletions
| @@ -1,5 +1,26 @@  2003-08-30  Havoc Pennington  <hp@pobox.com> +	* test/data/valid-config-files/system.d/test.conf: change to  +	root for the user so warnings don't get printed + +	* dbus/dbus-message.c: add dbus_message_get_path, +	dbus_message_set_path +	 +	* dbus/dbus-object-tree.c (do_test_dispatch): add test of +	dispatching to a path + +	* dbus/dbus-string.c (_dbus_string_validate_path): add + +	* dbus/dbus-marshal.c (_dbus_demarshal_object_path): implement +	(_dbus_marshal_object_path): implement + +	* dbus/dbus-protocol.h (DBUS_HEADER_FIELD_PATH): new header field  +	to contain the path to the target object +	(DBUS_HEADER_FIELD_SENDER_SERVICE): rename +	DBUS_HEADER_FIELD_SENDER to explicitly say it's the sender service + +2003-08-30  Havoc Pennington  <hp@pobox.com> +  	* dbus/dbus-object-tree.c: write tests and fix the discovered bugs  2003-08-29  Havoc Pennington  <hp@pobox.com> diff --git a/bus/dispatch.c b/bus/dispatch.c index 16102aa0..2f2e9e9d 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -727,9 +727,10 @@ check_hello_message (BusContext     *context,    acquired = NULL;    message = NULL; -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "Hello", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "Hello");    if (message == NULL)      return TRUE; @@ -958,9 +959,10 @@ check_nonexistent_service_activation (BusContext     *context,    dbus_error_init (&error); -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "ActivateService", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "ActivateService");    if (message == NULL)      return TRUE; @@ -1341,9 +1343,10 @@ check_send_exit_to_service (BusContext     *context,    retval = FALSE;    /* Kill off the test service by sending it a quit message */ -  message = dbus_message_new_method_call ("org.freedesktop.TestSuite", -                                          "Exit", -                                          service_name); +  message = dbus_message_new_method_call (service_name, +                                          "/org/freedesktop/TestSuite", +                                          "org.freedesktop.TestSuite", +                                          "Exit");    if (message == NULL)      { @@ -1510,9 +1513,10 @@ check_existent_service_activation (BusContext     *context,    dbus_error_init (&error); -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "ActivateService", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "ActivateService");    if (message == NULL)      return TRUE; @@ -1720,9 +1724,10 @@ check_segfault_service_activation (BusContext     *context,    dbus_error_init (&error); -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "ActivateService", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "ActivateService");    if (message == NULL)      return TRUE; diff --git a/bus/driver.c b/bus/driver.c index 7fd9cd87..61bfe1c5 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -49,7 +49,8 @@ bus_driver_send_service_deleted (const char     *service_name,    _dbus_verbose ("sending service deleted: %s\n", service_name); -  message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,                                       "ServiceDeleted");    if (message == NULL) @@ -84,7 +85,8 @@ bus_driver_send_service_created (const char     *service_name,    _DBUS_ASSERT_ERROR_IS_CLEAR (error); -  message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,                                       "ServiceCreated");    if (message == NULL) @@ -125,7 +127,8 @@ bus_driver_send_service_lost (DBusConnection *connection,    _DBUS_ASSERT_ERROR_IS_CLEAR (error); -  message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,                                       "ServiceLost");    if (message == NULL) @@ -167,7 +170,8 @@ bus_driver_send_service_acquired (DBusConnection *connection,    _DBUS_ASSERT_ERROR_IS_CLEAR (error); -  message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,                                       "ServiceAcquired");    if (message == NULL) diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 89a2d12b..a38b4a26 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -403,10 +403,10 @@ dbus_bus_register (DBusConnection *connection,        return TRUE;      } -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "Hello", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); -			       +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "Hello");     if (!message)      { @@ -522,9 +522,10 @@ dbus_bus_acquire_service (DBusConnection *connection,    _dbus_return_val_if_fail (service_name != NULL, 0);    _dbus_return_val_if_error_is_set (error, 0); -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "AcquireService", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "AcquireService");    if (message == NULL)      { @@ -596,9 +597,10 @@ dbus_bus_service_exists (DBusConnection *connection,    _dbus_return_val_if_fail (service_name != NULL, FALSE);    _dbus_return_val_if_error_is_set (error, FALSE); -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "ServiceExists", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "ServiceExists");    if (message == NULL)      {        _DBUS_SET_OOM (error); @@ -659,9 +661,10 @@ dbus_bus_activate_service (DBusConnection *connection,    DBusMessage *msg;    DBusMessage *reply; -  msg = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                      "ActivateService", -                                      DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                      DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                      "ActivateService");    if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name,  			  	 DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID)) diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 0c384594..86678673 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -825,7 +825,8 @@ _dbus_connection_new_for_transport (DBusTransport *transport)    if (io_path_cond == NULL)      goto error; -  disconnect_message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, +  disconnect_message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_LOCAL, +                                                DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,                                                  "Disconnected");    if (disconnect_message == NULL) @@ -2522,7 +2523,7 @@ dbus_connection_dispatch (DBusConnection *connection)    /* We're still protected from dispatch() reentrancy here     * since we acquired the dispatcher     */ -  _dbus_verbose ("  running object handler on message %p (%s)\n", +  _dbus_verbose ("  running object path dispatch on message %p (%s)\n",                   message,                   dbus_message_get_interface (message) ?                   dbus_message_get_interface (message) : diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 12ad0682..0b346530 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -200,7 +200,6 @@ void                  dbus_connection_send_preallocated      (DBusConnection  /* Object tree functionality */  typedef void              (* DBusObjectPathUnregisterFunction) (DBusConnection  *connection, -                                                                const char     **path,                                                                  void            *user_data);  typedef DBusHandlerResult (* DBusObjectPathMessageFunction)    (DBusConnection  *connection,                                                                  DBusMessage     *message, diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 449dd33a..6343056e 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -871,8 +871,6 @@ _dbus_marshal_string_array (DBusString  *str,  /**   * Marshals an object path value. - * - * @todo implement this function   *    * @param str the string to append the marshalled value to   * @param byte_order the byte order to use @@ -886,7 +884,41 @@ _dbus_marshal_object_path (DBusString            *str,                             const char           **path,                             int                    path_len)  { +  int array_start, old_string_len; +  int i; +   +  old_string_len = _dbus_string_get_length (str); +   +  /* Set the length to 0 temporarily */ +  if (!_dbus_marshal_uint32 (str, byte_order, 0)) +    goto nomem; + +  array_start = _dbus_string_get_length (str); +   +  i = 0; +  while (i < path_len) +    { +      if (!_dbus_string_append_byte (str, '/')) +        goto nomem; +       +      if (!_dbus_string_append (str, path[0])) +        goto nomem; + +      ++i; +    } + +  /* Write the length now that we know it */ +  _dbus_marshal_set_uint32 (str, byte_order, +			    _DBUS_ALIGN_VALUE (old_string_len, sizeof(dbus_uint32_t)), +			    _dbus_string_get_length (str) - array_start);   +    return TRUE; + + nomem: +  /* Restore the previous length */ +  _dbus_string_set_length (str, old_string_len); +   +  return FALSE;  }  static dbus_uint32_t @@ -1438,10 +1470,10 @@ _dbus_demarshal_string_array (const DBusString   *str,    return FALSE;  } +#define VERBOSE_DECOMPOSE 0 +  /**   * Demarshals an object path. - * - * @todo implement this function   *    * @param str the string containing the data   * @param byte_order the byte order @@ -1458,7 +1490,82 @@ _dbus_demarshal_object_path (const DBusString *str,                               char           ***path,                               int              *path_len)  { +  int len; +  char **retval; +  const char *data; +  int n_components; +  int i, j, comp; +   +  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); +  data = _dbus_string_get_const_data_len (str, pos, len + 1); +  _dbus_assert (data != NULL); + +#if VERBOSE_DECOMPOSE +  _dbus_verbose ("Decomposing path \"%s\"\n", +                 data); +#endif +   +  n_components = 0; +  i = 0; +  while (i < len) +    { +      if (data[i] == '/') +        n_components += 1; +      ++i; +    } +   +  retval = dbus_new0 (char*, n_components + 1); + +  if (retval == NULL) +    return FALSE; + +  comp = 0; +  i = 0; +  while (i < len) +    { +      if (data[i] == '/') +        ++i; +      j = i; + +      while (j < len && data[j] != '/') +        ++j; + +      /* Now [i, j) is the path component */ +      _dbus_assert (i < j); +      _dbus_assert (data[i] != '/'); +      _dbus_assert (j == len || data[j] == '/'); + +#if VERBOSE_DECOMPOSE +      _dbus_verbose ("  (component in [%d,%d))\n", +                     i, j); +#endif +       +      retval[comp] = _dbus_memdup (&data[i], j - i + 1); +      if (retval[comp] == NULL) +        { +          dbus_free_string_array (retval); +          return FALSE; +        } +      retval[comp][j-i] = '\0'; +#if VERBOSE_DECOMPOSE +      _dbus_verbose ("  (component %d = \"%s\")\n", +                     comp, retval[comp]); +#endif + +      ++comp; +      i = j; +    } +  _dbus_assert (i == len); +  _dbus_assert (retval[0] != NULL); +   +  *path = retval; +  if (path_len) +    *path_len = n_components; +  if (new_pos) +    *new_pos = pos + len + 1; +   +  return TRUE;  }  /**  @@ -1514,6 +1621,7 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str,        *end_pos = _DBUS_ALIGN_VALUE (pos, 8) + 8;        break; +    case DBUS_TYPE_OBJECT_PATH:      case DBUS_TYPE_STRING:        {  	int len; @@ -1540,8 +1648,7 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str,  	*end_pos = pos + len;        }        break; - -    case DBUS_TYPE_OBJECT_PATH: +            case DBUS_TYPE_ARRAY:        {  	int len; @@ -1917,6 +2024,7 @@ _dbus_marshal_validate_arg (const DBusString *str,        }        break; +    case DBUS_TYPE_OBJECT_PATH:      case DBUS_TYPE_STRING:        {  	int len; @@ -1930,6 +2038,12 @@ _dbus_marshal_validate_arg (const DBusString *str,          if (!validate_string (str, pos, len, end_pos))            return FALSE; + +        if (type == DBUS_TYPE_OBJECT_PATH) +          { +            if (!_dbus_string_validate_path (str, pos, len)) +              return FALSE; +          }        }        break; @@ -2521,7 +2635,6 @@ _dbus_marshal_test (void)    s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL);    _dbus_assert (strcmp (s, "Hello") == 0);    dbus_free (s); -    _dbus_string_free (&str); diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index f779c8c1..6d162310 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -288,6 +288,56 @@ message_type_from_string (const DBusString *str,      return -1;  } +static dbus_bool_t +append_string_field (DBusString *dest, +                     int         endian, +                     const char *field_name, +                     int         type, +                     const char *value) +{ +  int len; +   +  if (!_dbus_string_align_length (dest, 4)) +    { +      _dbus_warn ("could not align field name\n"); +      return FALSE; +    } + +  if (!_dbus_string_append (dest, field_name)) +    { +      _dbus_warn ("couldn't append field name\n"); +      return FALSE; +    } +   +  if (!_dbus_string_append_byte (dest, type)) +    { +      _dbus_warn ("could not append typecode byte\n"); +      return FALSE; +    } + +  len = strlen (value); + +  if (!_dbus_marshal_uint32 (dest, endian, len)) +    { +      _dbus_warn ("couldn't append string length\n"); +      return FALSE; +    } +   +  if (!_dbus_string_append (dest, value)) +    { +      _dbus_warn ("couldn't append field value\n"); +      return FALSE; +    } + +  if (!_dbus_string_append_byte (dest, 0)) +    { +      _dbus_warn ("couldn't append string nul term\n"); +      return FALSE; +    } + +  return TRUE; +} +  /**   * Reads the given filename, which should be in "message description   * language" (look at some examples), and builds up the message data @@ -298,6 +348,7 @@ message_type_from_string (const DBusString *str,   * The file format is:   * @code   *   VALID_HEADER <type> normal header; byte order, type, padding, header len, body len, serial + *   REQUIRED_FIELDS add required fields with placeholder values   *   BIG_ENDIAN switch to big endian   *   LITTLE_ENDIAN switch to little endian   *   OPPOSITE_ENDIAN switch to opposite endian @@ -322,6 +373,7 @@ message_type_from_string (const DBusString *str,   *   UINT64 <N> marshals a UINT64   *   DOUBLE <N> marshals a double   *   STRING 'Foo' marshals a string + *   OBJECT_PATH '/foo/bar' marshals an object path   *   BYTE_ARRAY { 'a', 3, 4, 5, 6} marshals a BYTE array   *   BOOLEAN_ARRAY { false, true, false} marshals a BOOLEAN array   *   INT32_ARRAY { 3, 4, 5, 6} marshals an INT32 array @@ -468,6 +520,25 @@ _dbus_message_data_load (DBusString       *dest,              }          }        else if (_dbus_string_starts_with_c_str (&line, +                                               "REQUIRED_FIELDS")) +        { +          if (!append_string_field (dest, endian, +                                    DBUS_HEADER_FIELD_INTERFACE, +                                    DBUS_TYPE_STRING, +                                    "org.freedesktop.BlahBlahInterface")) +            goto parse_failed; +          if (!append_string_field (dest, endian, +                                    DBUS_HEADER_FIELD_MEMBER, +                                    DBUS_TYPE_STRING, +                                    "BlahBlahMethod")) +            goto parse_failed; +          if (!append_string_field (dest, endian, +                                    DBUS_HEADER_FIELD_PATH, +                                    DBUS_TYPE_OBJECT_PATH, +                                    "/blah/blah/path")) +            goto parse_failed; +        } +      else if (_dbus_string_starts_with_c_str (&line,                                                 "BIG_ENDIAN"))          {            endian = DBUS_BIG_ENDIAN; @@ -648,6 +719,8 @@ _dbus_message_data_load (DBusString       *dest,              code = DBUS_TYPE_DOUBLE;            else if (_dbus_string_starts_with_c_str (&line, "STRING"))              code = DBUS_TYPE_STRING; +          else if (_dbus_string_starts_with_c_str (&line, "OBJECT_PATH")) +            code = DBUS_TYPE_OBJECT_PATH;            else if (_dbus_string_starts_with_c_str (&line, "NAMED"))              code = DBUS_TYPE_NAMED;            else if (_dbus_string_starts_with_c_str (&line, "ARRAY")) @@ -1270,6 +1343,36 @@ _dbus_message_data_load (DBusString       *dest,            PERFORM_UNALIGN (dest);          } +      else if (_dbus_string_starts_with_c_str (&line, +                                               "OBJECT_PATH")) +        { +          SAVE_FOR_UNALIGN (dest, 4); +          int size_offset; +          int old_len; +           +          _dbus_string_delete_first_word (&line); +           +          size_offset = _dbus_string_get_length (dest); +          size_offset = _DBUS_ALIGN_VALUE (size_offset, 4); +          if (!_dbus_marshal_uint32 (dest, endian, 0)) +            { +              _dbus_warn ("Failed to append string size\n"); +              goto parse_failed; +            } + +          old_len = _dbus_string_get_length (dest); +          if (!append_quoted_string (dest, &line, 0, NULL)) +            { +              _dbus_warn ("Failed to append quoted string\n"); +              goto parse_failed; +            } + +          _dbus_marshal_set_uint32 (dest, endian, size_offset, +                                    /* subtract 1 for nul */ +                                    _dbus_string_get_length (dest) - old_len - 1); +           +          PERFORM_UNALIGN (dest); +        }              else          goto parse_failed; diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 9b87c3d9..090bdfc7 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -47,11 +47,12 @@ enum    FIELD_HEADER_LENGTH,    FIELD_BODY_LENGTH,    FIELD_CLIENT_SERIAL, +  FIELD_PATH,    FIELD_INTERFACE,    FIELD_MEMBER,    FIELD_ERROR_NAME,    FIELD_SERVICE, -  FIELD_SENDER, +  FIELD_SENDER_SERVICE,    FIELD_REPLY_SERIAL,    FIELD_LAST @@ -62,11 +63,12 @@ static dbus_bool_t field_is_named[FIELD_LAST] =    FALSE, /* FIELD_HEADER_LENGTH */    FALSE, /* FIELD_BODY_LENGTH */    FALSE, /* FIELD_CLIENT_SERIAL */ +  TRUE,  /* FIELD_PATH */    TRUE,  /* FIELD_INTERFACE */    TRUE,  /* FIELD_MEMBER */    TRUE,  /* FIELD_ERROR_NAME */    TRUE,  /* FIELD_SERVICE */ -  TRUE,  /* FIELD_SENDER */ +  TRUE,  /* FIELD_SENDER_SERVICE */    TRUE   /* FIELD_REPLY_SERIAL */  }; @@ -289,6 +291,31 @@ get_string_field (DBusMessage *message,    return data + (offset + 4);   } +/* returns FALSE if no memory, TRUE with NULL path if no field */ +static dbus_bool_t +get_path_field_decomposed (DBusMessage  *message, +                           int           field, +                           char       ***path) +{ +  int offset; + +  offset = message->header_fields[field].offset; + +  _dbus_assert (field < FIELD_LAST); +   +  if (offset < 0) +    { +      *path = NULL; +      return TRUE; +    } + +  return _dbus_demarshal_object_path (&message->header, +                                      message->byte_order, +                                      offset, +                                      NULL, +                                      path, NULL); +} +  #ifdef DBUS_BUILD_TESTS  static dbus_bool_t  append_int_field (DBusMessage *message, @@ -394,6 +421,7 @@ append_uint_field (DBusMessage *message,  static dbus_bool_t  append_string_field (DBusMessage *message,                       int          field, +                     int          type,                       const char  *name,                       const char  *value)  { @@ -411,7 +439,7 @@ append_string_field (DBusMessage *message,    if (!_dbus_string_append_len (&message->header, name, 4))      goto failed; -  if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING)) +  if (!_dbus_string_append_byte (&message->header, type))      goto failed;    if (!_dbus_string_align_length (&message->header, 4)) @@ -580,6 +608,7 @@ set_uint_field (DBusMessage  *message,  static dbus_bool_t  set_string_field (DBusMessage *message,                    int          field, +                  int          type,                    const char  *value)  {    int offset = message->header_fields[field].offset; @@ -593,24 +622,28 @@ set_string_field (DBusMessage *message,        switch (field)          { -        case FIELD_SENDER: -          return append_string_field (message, field, -                                      DBUS_HEADER_FIELD_SENDER, +        case FIELD_PATH: +          return append_string_field (message, field, type, +                                      DBUS_HEADER_FIELD_PATH, +                                      value); +        case FIELD_SENDER_SERVICE: +          return append_string_field (message, field, type, +                                      DBUS_HEADER_FIELD_SENDER_SERVICE,                                        value);          case FIELD_INTERFACE: -          return append_string_field (message, field, +          return append_string_field (message, field, type,                                        DBUS_HEADER_FIELD_INTERFACE,                                        value);          case FIELD_MEMBER: -          return append_string_field (message, field, +          return append_string_field (message, field, type,                                        DBUS_HEADER_FIELD_MEMBER,                                        value);          case FIELD_ERROR_NAME: -          return append_string_field (message, field, +          return append_string_field (message, field, type,                                        DBUS_HEADER_FIELD_ERROR_NAME,                                        value);          case FIELD_SERVICE: -          return append_string_field (message, field, +          return append_string_field (message, field, type,                                        DBUS_HEADER_FIELD_SERVICE,                                        value);          default: @@ -829,10 +862,11 @@ _dbus_message_remove_size_counter (DBusMessage  *message,  static dbus_bool_t  dbus_message_create_header (DBusMessage *message,                              int          type, +                            const char  *service, +                            const char  *path,                              const char  *interface,                              const char  *member, -                            const char  *error_name, -                            const char  *service) +                            const char  *error_name)  {    unsigned int flags; @@ -865,11 +899,21 @@ dbus_message_create_header (DBusMessage *message,    if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1))      return FALSE; -  /* Marshal message service */ +  /* Marshal all the fields (Marshall Fields?) */ +   +  if (path != NULL) +    { +      if (!append_string_field (message, +                                FIELD_PATH, DBUS_TYPE_OBJECT_PATH, +                                DBUS_HEADER_FIELD_PATH, +                                path)) +        return FALSE; +    } +      if (service != NULL)      {        if (!append_string_field (message, -                                FIELD_SERVICE, +                                FIELD_SERVICE, DBUS_TYPE_STRING,                                  DBUS_HEADER_FIELD_SERVICE,                                  service))          return FALSE; @@ -878,7 +922,7 @@ dbus_message_create_header (DBusMessage *message,    if (interface != NULL)      {        if (!append_string_field (message, -                                FIELD_INTERFACE, +                                FIELD_INTERFACE, DBUS_TYPE_STRING,                                  DBUS_HEADER_FIELD_INTERFACE,                                  interface))          return FALSE; @@ -887,7 +931,7 @@ dbus_message_create_header (DBusMessage *message,    if (member != NULL)      {        if (!append_string_field (message, -                                FIELD_MEMBER, +                                FIELD_MEMBER, DBUS_TYPE_STRING,                                  DBUS_HEADER_FIELD_MEMBER,                                  member))          return FALSE; @@ -896,7 +940,7 @@ dbus_message_create_header (DBusMessage *message,    if (error_name != NULL)      {        if (!append_string_field (message, -                                FIELD_ERROR_NAME, +                                FIELD_ERROR_NAME, DBUS_TYPE_STRING,                                  DBUS_HEADER_FIELD_ERROR_NAME,                                  error_name))          return FALSE; @@ -1015,7 +1059,7 @@ dbus_message_new (int message_type)    if (!dbus_message_create_header (message,                                     message_type, -                                   NULL, NULL, NULL, NULL)) +                                   NULL, NULL, NULL, NULL, NULL))      {        dbus_message_unref (message);        return NULL; @@ -1029,22 +1073,27 @@ dbus_message_new (int message_type)   * object. Returns #NULL if memory can't be allocated for the   * message. The service may be #NULL in which case no service is set;   * this is appropriate when using D-BUS in a peer-to-peer context (no - * message bus). - * + * message bus). The interface may be #NULL, which means that + * if multiple methods with the given name exist it is undefined + * which one will be invoked. +  * + * @param service service that the message should be sent to or #NULL + * @param path object path the message should be sent to   * @param interface interface to invoke method on   * @param method method to invoke - * @param destination_service service that the message should be sent to or #NULL + *    * @returns a new DBusMessage, free with dbus_message_unref()   * @see dbus_message_unref()   */  DBusMessage* -dbus_message_new_method_call (const char *interface, -                              const char *method, -                              const char *destination_service)		   +dbus_message_new_method_call (const char *service, +                              const char *path, +                              const char *interface, +                              const char *method)  {    DBusMessage *message; -  _dbus_return_val_if_fail (interface != NULL, NULL); +  _dbus_return_val_if_fail (path != NULL, NULL);    _dbus_return_val_if_fail (method != NULL, NULL);    message = dbus_message_new_empty_header (); @@ -1053,7 +1102,7 @@ dbus_message_new_method_call (const char *interface,    if (!dbus_message_create_header (message,                                     DBUS_MESSAGE_TYPE_METHOD_CALL, -                                   interface, method, NULL, destination_service)) +                                   service, path, interface, method, NULL))      {        dbus_message_unref (message);        return NULL; @@ -1080,8 +1129,8 @@ dbus_message_new_method_return (DBusMessage *method_call)    _dbus_return_val_if_fail (method_call != NULL, NULL);    sender = get_string_field (method_call, -                             FIELD_SENDER, NULL); - +                             FIELD_SENDER_SERVICE, NULL); +      /* sender is allowed to be null here in peer-to-peer case */    message = dbus_message_new_empty_header (); @@ -1090,7 +1139,7 @@ dbus_message_new_method_return (DBusMessage *method_call)    if (!dbus_message_create_header (message,                                     DBUS_MESSAGE_TYPE_METHOD_RETURN, -                                   NULL, NULL, NULL, sender)) +                                   sender, NULL, NULL, NULL, NULL))      {        dbus_message_unref (message);        return NULL; @@ -1118,11 +1167,14 @@ dbus_message_new_method_return (DBusMessage *method_call)   * @see dbus_message_unref()   */  DBusMessage* -dbus_message_new_signal (const char *interface, +dbus_message_new_signal (const char *path, +                         const char *interface,                           const char *name)  {    DBusMessage *message; +  _dbus_return_val_if_fail (path != NULL, NULL); +  _dbus_return_val_if_fail (interface != NULL, NULL);    _dbus_return_val_if_fail (name != NULL, NULL);    message = dbus_message_new_empty_header (); @@ -1131,7 +1183,7 @@ dbus_message_new_signal (const char *interface,    if (!dbus_message_create_header (message,                                     DBUS_MESSAGE_TYPE_SIGNAL, -                                   interface, name, NULL, NULL)) +                                   NULL, path, interface, name, NULL))      {        dbus_message_unref (message);        return NULL; @@ -1162,7 +1214,7 @@ dbus_message_new_error (DBusMessage *reply_to,    _dbus_return_val_if_fail (error_name != NULL, NULL);    sender = get_string_field (reply_to, -                             FIELD_SENDER, NULL); +                             FIELD_SENDER_SERVICE, NULL);    /* sender may be NULL for non-message-bus case or     * when the message bus is dealing with an unregistered @@ -1174,7 +1226,7 @@ dbus_message_new_error (DBusMessage *reply_to,    if (!dbus_message_create_header (message,                                     DBUS_MESSAGE_TYPE_ERROR, -                                   NULL, NULL, error_name, sender)) +                                   sender, NULL, NULL, NULL, error_name))      {        dbus_message_unref (message);        return NULL; @@ -1353,6 +1405,78 @@ dbus_message_get_type (DBusMessage *message)  }  /** + * Sets the object path this message is being sent to (for + * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being + * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL). + * + * @param message the message + * @param object_path the path + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_path (DBusMessage   *message, +                       const char    *object_path) +{ +  _dbus_return_val_if_fail (message != NULL, FALSE); +  _dbus_return_val_if_fail (!message->locked, FALSE); +   +  if (object_path == NULL) +    { +      delete_string_field (message, FIELD_PATH); +      return TRUE; +    } +  else +    { +      return set_string_field (message, +                               FIELD_PATH, +                               DBUS_TYPE_OBJECT_PATH, +                               object_path); +    } +} + +/** + * Gets the object path this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted + * from (for DBUS_MESSAGE_TYPE_SIGNAL). + * + * @param message the message + * @returns the path (should not be freed) + */ +const char* +dbus_message_get_path (DBusMessage   *message) +{ +  _dbus_return_val_if_fail (message != NULL, NULL); +   +  return get_string_field (message, FIELD_PATH, NULL); +} + +/** + * Gets the object path this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted + * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed + * format (one array element per path component). + * Free the returned array with dbus_free_string_array(). + * + * An empty but non-NULL path array means the path "/". + * So the path "/foo/bar" becomes { "foo", "bar", NULL } + * and the path "/" becomes { NULL }. + * + * @param message the message + * @param path place to store allocated array of path components; #NULL set here if no path field exists + * @returns #FALSE if no memory to allocate the array + */ +dbus_bool_t +dbus_message_get_path_decomposed (DBusMessage   *message, +                                  char        ***path) +{ +  _dbus_return_val_if_fail (message != NULL, FALSE); +  _dbus_return_val_if_fail (path != NULL, FALSE); + +  return get_path_field_decomposed (message, FIELD_PATH, +                                    path); +} + +/**   * Sets the interface this message is being sent to   * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or   * the interface a signal is being emitted from @@ -1378,6 +1502,7 @@ dbus_message_set_interface (DBusMessage  *message,      {        return set_string_field (message,                                 FIELD_INTERFACE, +                               DBUS_TYPE_STRING,                                 interface);      }  } @@ -1425,6 +1550,7 @@ dbus_message_set_member (DBusMessage  *message,      {        return set_string_field (message,                                 FIELD_MEMBER, +                               DBUS_TYPE_STRING,                                 member);      }  } @@ -1469,6 +1595,7 @@ dbus_message_set_error_name (DBusMessage  *message,      {        return set_string_field (message,                                 FIELD_ERROR_NAME, +                               DBUS_TYPE_STRING,                                 error_name);      }  } @@ -1510,6 +1637,7 @@ dbus_message_set_destination (DBusMessage  *message,      {        return set_string_field (message,                                 FIELD_SERVICE, +                               DBUS_TYPE_STRING,                                 destination);      }  } @@ -3977,13 +4105,14 @@ dbus_message_set_sender (DBusMessage  *message,    if (sender == NULL)      { -      delete_string_field (message, FIELD_SENDER); +      delete_string_field (message, FIELD_SENDER_SERVICE);        return TRUE;      }    else      {        return set_string_field (message, -                               FIELD_SENDER, +                               FIELD_SENDER_SERVICE, +                               DBUS_TYPE_STRING,                                 sender);      }  } @@ -4046,7 +4175,7 @@ dbus_message_get_sender (DBusMessage *message)  {    _dbus_return_val_if_fail (message != NULL, NULL); -  return get_string_field (message, FIELD_SENDER, NULL); +  return get_string_field (message, FIELD_SENDER_SERVICE, NULL);  }  static dbus_bool_t @@ -4436,6 +4565,10 @@ _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,                         (((dbus_uint32_t)c) << 8)  |     \                         ((dbus_uint32_t)d)) +/** DBUS_HEADER_FIELD_PATH packed into a dbus_uint32_t */ +#define DBUS_HEADER_FIELD_PATH_AS_UINT32    \ +  FOUR_CHARS_TO_UINT32 ('p', 'a', 't', 'h') +  /** DBUS_HEADER_FIELD_INTERFACE packed into a dbus_uint32_t */  #define DBUS_HEADER_FIELD_INTERFACE_AS_UINT32    \    FOUR_CHARS_TO_UINT32 ('i', 'f', 'c', 'e') @@ -4456,9 +4589,9 @@ _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,  #define DBUS_HEADER_FIELD_REPLY_AS_UINT32   \    FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y') -/** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */ -#define DBUS_HEADER_FIELD_SENDER_AS_UINT32  \ -  FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r') +/** DBUS_HEADER_FIELD_SENDER_SERVICE Packed into a dbus_uint32_t */ +#define DBUS_HEADER_FIELD_SENDER_SERVICE_AS_UINT32  \ +  FOUR_CHARS_TO_UINT32 ('s', 'd', 'r', 's')  static dbus_bool_t  decode_string_field (const DBusString   *data, @@ -4530,7 +4663,7 @@ decode_string_field (const DBusString   *data,          }      }    else if (field == FIELD_SERVICE || -           field == FIELD_SENDER) +           field == FIELD_SENDER_SERVICE)      {        if (!_dbus_string_validate_service (&tmp, 0, _dbus_string_get_length (&tmp)))          { @@ -4538,7 +4671,7 @@ decode_string_field (const DBusString   *data,                           field_name, _dbus_string_get_const_data (&tmp));            return FALSE;          } -    }   +    }    else      {        _dbus_assert_not_reached ("Unknown field\n"); @@ -4601,7 +4734,7 @@ decode_header_data (const DBusString   *data,            return FALSE;          } -      field =_dbus_string_get_const_data_len (data, pos, 4); +      field = _dbus_string_get_const_data_len (data, pos, 4);        pos += 4;        _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field); @@ -4654,12 +4787,51 @@ decode_header_data (const DBusString   *data,              return FALSE;            break; -	case DBUS_HEADER_FIELD_SENDER_AS_UINT32: +	case DBUS_HEADER_FIELD_SENDER_SERVICE_AS_UINT32:            if (!decode_string_field (data, fields, pos, type, -                                    FIELD_SENDER, -                                    DBUS_HEADER_FIELD_SENDER)) +                                    FIELD_SENDER_SERVICE, +                                    DBUS_HEADER_FIELD_SENDER_SERVICE))              return FALSE;  	  break; + +	case DBUS_HEADER_FIELD_PATH_AS_UINT32: + +          /* Path was already validated as part of standard +           * type validation, since there's an OBJECT_PATH +           * type. +           */ +           +          if (fields[FIELD_PATH].offset >= 0) +            { +              _dbus_verbose ("%s field provided twice\n", +                             DBUS_HEADER_FIELD_PATH); +              return FALSE; +            } +          if (type != DBUS_TYPE_OBJECT_PATH) +            { +              _dbus_verbose ("%s field has wrong type\n", DBUS_HEADER_FIELD_PATH); +              return FALSE; +            } + +          fields[FIELD_PATH].offset = _DBUS_ALIGN_VALUE (pos, 4); + +          /* No forging signals from the local path */ +          { +            const char *s; +            s = _dbus_string_get_const_data_len (data, +                                                 fields[FIELD_PATH].offset, +                                                 _dbus_string_get_length (data) - +                                                 fields[FIELD_PATH].offset); +            if (strcmp (s, DBUS_PATH_ORG_FREEDESKTOP_LOCAL) == 0) +              { +                _dbus_verbose ("Message is on the local path\n"); +                return FALSE; +              } +          } +           +          _dbus_verbose ("Found path at offset %d\n", +                         fields[FIELD_PATH].offset); +	  break;  	case DBUS_HEADER_FIELD_REPLY_AS_UINT32:            if (fields[FIELD_REPLY_SERIAL].offset >= 0) @@ -4707,6 +4879,13 @@ decode_header_data (const DBusString   *data,      {      case DBUS_MESSAGE_TYPE_SIGNAL:      case DBUS_MESSAGE_TYPE_METHOD_CALL: +      if (fields[FIELD_PATH].offset < 0) +        { +          _dbus_verbose ("No %s field provided\n", +                         DBUS_HEADER_FIELD_PATH); +          return FALSE; +        } +      /* FIXME make this optional, at least for method calls */        if (fields[FIELD_INTERFACE].offset < 0)          {            _dbus_verbose ("No %s field provided\n", @@ -6310,9 +6489,10 @@ _dbus_message_test (const char *test_data_dir)    _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); -  message = dbus_message_new_method_call ("Foo.TestInterface", -                                          "TestMethod", -                                          "org.freedesktop.DBus.TestService"); +  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", +                                          "/org/freedesktop/TestPath", +                                          "Foo.TestInterface", +                                          "TestMethod");    _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));    _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface",                                               "TestMethod")); @@ -6333,9 +6513,10 @@ _dbus_message_test (const char *test_data_dir)    dbus_message_unref (message);    /* Test the vararg functions */ -  message = dbus_message_new_method_call ("Foo.TestInterface", -                                          "TestMethod", -                                          "org.freedesktop.DBus.TestService"); +  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", +                                          "/org/freedesktop/TestPath", +                                          "Foo.TestInterface", +                                          "TestMethod");    _dbus_message_set_serial (message, 1);    dbus_message_append_args (message,  			    DBUS_TYPE_INT32, -0x12345678, @@ -6406,9 +6587,11 @@ _dbus_message_test (const char *test_data_dir)    dbus_message_unref (message);    dbus_message_unref (copy); -  message = dbus_message_new_method_call ("Foo.TestInterface", -                                          "TestMethod", -                                          "org.freedesktop.DBus.TestService"); +  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", +                                          "/org/freedesktop/TestPath", +                                          "Foo.TestInterface", +                                          "TestMethod"); +    _dbus_message_set_serial (message, 1);    dbus_message_set_reply_serial (message, 0x12345678); diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index 526cf971..def65379 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -58,11 +58,13 @@ struct DBusMessageIter  };  DBusMessage* dbus_message_new               (int          message_type); -DBusMessage* dbus_message_new_method_call   (const char  *interface, -                                             const char  *method, -                                             const char  *destination_service); +DBusMessage* dbus_message_new_method_call   (const char  *service, +                                             const char  *path, +                                             const char  *interface, +                                             const char  *method);  DBusMessage* dbus_message_new_method_return (DBusMessage *method_call); -DBusMessage* dbus_message_new_signal        (const char  *interface, +DBusMessage* dbus_message_new_signal        (const char  *path, +                                             const char  *interface,                                               const char  *name);  DBusMessage* dbus_message_new_error         (DBusMessage *reply_to,                                               const char  *error_name, @@ -73,6 +75,9 @@ DBusMessage *dbus_message_copy              (const DBusMessage *message);  void          dbus_message_ref              (DBusMessage   *message);  void          dbus_message_unref            (DBusMessage   *message);  int           dbus_message_get_type         (DBusMessage   *message); +dbus_bool_t   dbus_message_set_path         (DBusMessage   *message, +                                             const char    *object_path); +const char*   dbus_message_get_path         (DBusMessage   *message);  dbus_bool_t   dbus_message_set_interface    (DBusMessage   *message,                                               const char    *interface);  const char*   dbus_message_get_interface    (DBusMessage   *message); @@ -108,6 +113,9 @@ dbus_bool_t   dbus_message_set_reply_serial (DBusMessage   *message,                                               dbus_uint32_t  reply_serial);  dbus_uint32_t dbus_message_get_reply_serial (DBusMessage   *message); +dbus_bool_t   dbus_message_get_path_decomposed (DBusMessage   *message, +                                                char        ***path); +  dbus_bool_t dbus_message_append_args          (DBusMessage     *message,  					       int              first_arg_type,  					       ...); diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 379e2f04..24e402a2 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -36,12 +36,18 @@   * Types and functions related to DBusObjectTree. These   * are all internal.   * + * @todo this is totally broken, because of the following case: + *    /foo, /foo/bar, /foo/baz + *  if we then receive a message to /foo/baz we need to hand it + * to /foo/baz and /foo but not /foo/bar. So we should be + * using a real tree structure as with GConfListeners. + *   * @{   */  typedef struct DBusObjectSubtree DBusObjectSubtree; -static DBusObjectSubtree* _dbus_object_subtree_new   (const char                 **path, +static DBusObjectSubtree* _dbus_object_subtree_new   (const char                  *name,                                                        const DBusObjectPathVTable  *vtable,                                                        void                        *user_data);  static void               _dbus_object_subtree_ref   (DBusObjectSubtree           *subtree); @@ -52,41 +58,42 @@ struct DBusObjectTree    int                 refcount;    DBusConnection     *connection; -  /* Each subtree is a separate malloc block since that -   * lets us refcount them and maybe helps with -   * reentrancy issues when calling back to application code -   */ -  DBusObjectSubtree **subtrees; -  int                 n_subtrees; -  unsigned int        subtrees_sorted : 1; +  DBusObjectSubtree  *root;  };  struct DBusObjectSubtree  {    DBusAtomic                         refcount; +  DBusObjectSubtree                 *parent;    DBusObjectPathUnregisterFunction   unregister_function;    DBusObjectPathMessageFunction      message_function;    void                              *user_data; -  char                              *path[1]; /**< Allocated as large as necessary */ +  DBusObjectSubtree                **subtrees; +  int                                n_subtrees; +  unsigned int                       subtrees_sorted : 1; +  char                               name[1]; /**< Allocated as large as necessary */  };  DBusObjectTree*  _dbus_object_tree_new (DBusConnection *connection)  {    DBusObjectTree *tree; -   +    /* the connection passed in here isn't fully constructed,     * so don't do anything more than store a pointer to     * it     */ -   +    tree = dbus_new0 (DBusObjectTree, 1);    if (tree == NULL)      goto oom; -   +    tree->refcount = 1;    tree->connection = connection; -   +  tree->root = _dbus_object_subtree_new ("/", NULL, NULL); +  if (tree->root == NULL) +    goto oom; +    return tree;   oom: @@ -94,7 +101,7 @@ _dbus_object_tree_new (DBusConnection *connection)      {        dbus_free (tree);      } -   +    return NULL;  } @@ -117,55 +124,15 @@ _dbus_object_tree_unref (DBusObjectTree *tree)      {        _dbus_object_tree_free_all_unlocked (tree); -      dbus_free (tree->subtrees);        dbus_free (tree);      }  }  static int -path_cmp (const char **path_a, -          const char **path_b) -{ -  /* strcmp() considers a shorter string less than a longer string if -   * the shorter string is the initial part of the longer. We -   * consider a path with less elements less than a path with more -   * elements. -   */ -  int i; - -  i = 0; -  while (path_a[i] != NULL) -    { -      int v; -       -      if (path_b[i] == NULL) -        return 1; /* a is longer than b */ - -      _dbus_assert (path_a[i] != NULL); -      _dbus_assert (path_b[i] != NULL); -       -      v = strcmp (path_a[i], path_b[i]); - -      if (v != 0) -        return v; - -      ++i; -    } - -  _dbus_assert (path_a[i] == NULL); -  if (path_b[i] == NULL) -    return 0; -   -  /* b is longer than a */ -  return -1; -} - -static int  subtree_cmp (DBusObjectSubtree *subtree_a,               DBusObjectSubtree *subtree_b)  { -  return path_cmp ((const char**) subtree_a->path, -                   (const char**) subtree_b->path); +  return strcmp (subtree_a->name, subtree_b->name);  }  static int @@ -175,163 +142,198 @@ subtree_qsort_cmp (const void *a,    DBusObjectSubtree **subtree_a_p = (void*) a;    DBusObjectSubtree **subtree_b_p = (void*) b; -  return subtree_cmp (*subtree_a_p, *subtree_b_p);   -} - -/* Returns TRUE if container is a parent of child - */ -static dbus_bool_t -path_contains (const char **container, -               const char **child) -{ -  int i; - -  i = 0; -  while (child[i] != NULL) -    { -      int v; -       -      if (container[i] == NULL) -        return TRUE; /* container ran out, child continues; -                      * thus the container is a parent of the -                      * child. -                      */ - -      _dbus_assert (container[i] != NULL); -      _dbus_assert (child[i] != NULL); -       -      v = strcmp (container[i], child[i]); - -      if (v != 0) -        return FALSE; /* they overlap until here and then are different, -                       * not overlapping -                       */ - -      ++i; -    } - -  /* Child ran out; if container also did, they are equal; -   * otherwise, the child is a parent of the container. -   */ -  if (container[i] == NULL) -    return TRUE; /* equal is counted as containing */ -  else -    return FALSE; +  return subtree_cmp (*subtree_a_p, *subtree_b_p);  }  static void -ensure_sorted (DBusObjectTree *tree) +ensure_sorted (DBusObjectSubtree *subtree)  { -  if (tree->subtrees && !tree->subtrees_sorted) +  if (subtree->subtrees && !subtree->subtrees_sorted)      { -      qsort (tree->subtrees, -             tree->n_subtrees, +      qsort (subtree->subtrees, +             subtree->n_subtrees,               sizeof (DBusObjectSubtree*),               subtree_qsort_cmp); -      tree->subtrees_sorted = TRUE; +      subtree->subtrees_sorted = TRUE;      }  } -static dbus_bool_t -find_subtree (DBusObjectTree *tree, -              const char    **path, -              int            *idx_p) +#define VERBOSE_FIND 0 + +static DBusObjectSubtree* +find_subtree_recurse (DBusObjectSubtree  *subtree, +                      const char        **path, +                      dbus_bool_t         return_deepest_match, +                      dbus_bool_t         create_if_not_found, +                      int                *index_in_parent)  {    int i; -   -  if (tree->subtrees == NULL) -    return FALSE; -  ensure_sorted (tree);   +  _dbus_assert (!(return_deepest_match && create_if_not_found)); + +  if (path[0] == NULL) +    { +#if VERBOSE_FIND +      _dbus_verbose ("  path exhausted, returning %s\n", +                     subtree->name); +#endif +      return subtree; +    } -  /* FIXME this should be a binary search, -   * as that's the whole point of the sorting +#if VERBOSE_FIND +  _dbus_verbose ("  searching children of %s for %s\n", +                 subtree->name, path[0]); +#endif +   +  ensure_sorted (subtree); + +  /* FIXME we should do a binary search here instead +   * of O(n)     */ +    i = 0; -  while (i < tree->n_subtrees) +  while (i < subtree->n_subtrees)      {        int v; -      v = path_cmp (path, -                    (const char**) tree->subtrees[i]->path); +      v = strcmp (path[0], subtree->subtrees[i]->name); + +#if VERBOSE_FIND +      _dbus_verbose ("  %s cmp %s = %d\n", +                     path[0], subtree->subtrees[i]->name, +                     v); +#endif        if (v == 0)          { -          if (idx_p) -            *idx_p = i; -           -          return TRUE; +          if (index_in_parent) +            { +#if VERBOSE_FIND +              _dbus_verbose ("  storing parent index %d\n", i); +#endif +              *index_in_parent = i; +            } + +          if (return_deepest_match) +            { +              DBusObjectSubtree *next; + +              next = find_subtree_recurse (subtree->subtrees[i], +                                           &path[1], return_deepest_match, +                                           create_if_not_found, index_in_parent); +              if (next == NULL) +                { +#if VERBOSE_FIND +                  _dbus_verbose ("  no deeper match found, returning %s\n", +                                 subtree->name); +#endif +                  return subtree; +                } +              else +                return next; +            } +          else +            return find_subtree_recurse (subtree->subtrees[i], +                                         &path[1], return_deepest_match, +                                         create_if_not_found, index_in_parent);          }        else if (v < 0)          { -          return FALSE; +          goto not_found;          } -       +        ++i;      } -   -  return FALSE; -} -static dbus_bool_t -find_handler (DBusObjectTree *tree, -              const char    **path, -              int            *idx_p) -{ -  int i; -  int found_so_far; -   -  if (tree->subtrees == NULL) -    return FALSE; -   -  ensure_sorted (tree); + not_found: +#if VERBOSE_FIND +  _dbus_verbose ("  no match found, current tree %s, create_if_not_found = %d\n", +                 subtree->name, create_if_not_found); +#endif -  /* FIXME this should be a binary search, -   * as that's the whole point of the sorting -   */ -  found_so_far = -1; -  i = 0; -  while (i < tree->n_subtrees) +  if (create_if_not_found)      { -      /* Longer paths are after shorter, so we scan -       * for the latest containing path in the array. -       * If we did a binary search we'd start with -       * the first search match. -       */ -      if (path_contains ((const char**) tree->subtrees[i]->path, -                         path)) -        found_so_far = i; -      else if (found_so_far >= 0) -        break; /* no need to scan further */ +      DBusObjectSubtree* child; +      DBusObjectSubtree **new_subtrees; +      int new_n_subtrees; + +#if VERBOSE_FIND +      _dbus_verbose ("  creating subtree %s\n", +                     path[0]); +#endif -      ++i; -    } +      child = _dbus_object_subtree_new (path[0], +                                        NULL, NULL); +      if (child == NULL) +        return NULL; + +      /* FIXME we should do the "double alloc each time" standard thing */ +      new_n_subtrees = subtree->n_subtrees + 1; +      new_subtrees = dbus_realloc (subtree->subtrees, +                                   new_n_subtrees * sizeof (DBusObjectSubtree*)); +      if (new_subtrees == NULL) +        { +          child->unregister_function = NULL; +          child->message_function = NULL; +          _dbus_object_subtree_unref (child); +          return FALSE; +        } -  if (idx_p) -    *idx_p = found_so_far; +      new_subtrees[subtree->n_subtrees] = child; +      if (index_in_parent) +        *index_in_parent = subtree->n_subtrees; +      subtree->subtrees_sorted = FALSE; +      subtree->n_subtrees = new_n_subtrees; +      subtree->subtrees = new_subtrees; -  return FALSE; +      child->parent = subtree; + +      return find_subtree_recurse (child, +                                   &path[1], return_deepest_match, +                                   create_if_not_found, index_in_parent); +    } +  else +    return return_deepest_match ? subtree : NULL;  } -#ifndef DBUS_DISABLE_CHECKS -static void -check_already_exists (DBusObjectTree *tree, -                      const char    **path) +static DBusObjectSubtree* +find_subtree (DBusObjectTree *tree, +              const char    **path, +              int            *index_in_parent)  { -  int i; +  DBusObjectSubtree *subtree; -  i = 0; -  while (i < tree->n_subtrees) -    { -      if (path_cmp (path, (const char**) tree->subtrees[i]->path) == 0) -        { -          _dbus_warn ("New path (path[0] = %s) already registered\n", -                      path[0]); -        } -      ++i; -    } +#if VERBOSE_FIND +  _dbus_verbose ("Looking for exact registered subtree\n"); +#endif +   +  subtree = find_subtree_recurse (tree->root, path, FALSE, FALSE, index_in_parent); + +  if (subtree && subtree->message_function == NULL) +    return NULL; +  else +    return subtree;  } + +static DBusObjectSubtree* +find_handler (DBusObjectTree *tree, +              const char    **path) +{ +#if VERBOSE_FIND +  _dbus_verbose ("Looking for deepest handler\n");  #endif +  return find_subtree_recurse (tree->root, path, TRUE, FALSE, NULL); +} + +static DBusObjectSubtree* +ensure_subtree (DBusObjectTree *tree, +                const char    **path) +{ +#if VERBOSE_FIND +  _dbus_verbose ("Ensuring subtree\n"); +#endif +  return find_subtree_recurse (tree->root, path, FALSE, TRUE, NULL); +}  /**   * Registers a new subtree in the global object tree. @@ -349,37 +351,25 @@ _dbus_object_tree_register (DBusObjectTree              *tree,                              void                        *user_data)  {    DBusObjectSubtree  *subtree; -  DBusObjectSubtree **new_subtrees; -  int new_n_subtrees;    _dbus_assert (tree != NULL); -  _dbus_assert (vtable->message_function != NULL);   +  _dbus_assert (vtable->message_function != NULL);    _dbus_assert (path != NULL); -#ifndef DBUS_DISABLE_CHECKS -  check_already_exists (tree, path); -#endif -  _dbus_assert (path[0] != NULL); -   -  subtree = _dbus_object_subtree_new (path, vtable, user_data); + +  subtree = ensure_subtree (tree, path);    if (subtree == NULL)      return FALSE; -   -  /* FIXME we should do the "double alloc each time" standard thing */ -  new_n_subtrees = tree->n_subtrees + 1; -  new_subtrees = dbus_realloc (tree->subtrees, -                               new_n_subtrees * sizeof (DBusObjectSubtree*)); -  if (new_subtrees == NULL) + +  if (subtree->message_function != NULL)      { -      subtree->unregister_function = NULL; -      subtree->message_function = NULL; -      _dbus_object_subtree_unref (subtree); +      _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n", +                  path[0] ? path[0] : "null");        return FALSE;      } -  new_subtrees[tree->n_subtrees] = subtree; -  tree->subtrees_sorted = FALSE; -  tree->n_subtrees = new_n_subtrees; -  tree->subtrees = new_subtrees; +  subtree->message_function = vtable->message_function; +  subtree->unregister_function = vtable->unregister_function; +  subtree->user_data = user_data;    return TRUE;  } @@ -397,43 +387,102 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree          *tree,  {    int i;    DBusObjectSubtree *subtree; +  DBusObjectPathUnregisterFunction unregister_function; +  void *user_data; +  DBusConnection *connection;    _dbus_assert (path != NULL); -  _dbus_assert (path[0] != NULL); -  if (!find_subtree (tree, path, &i)) +  subtree = find_subtree (tree, path, &i); + +  if (subtree == NULL)      {        _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", -                  path[0], path[1] ? path[1] : "null"); +                  path[0] ? path[0] : "null", +                  path[1] ? path[1] : "null");        return;      } -  _dbus_assert (i >= 0); -   -  subtree = tree->subtrees[i]; - -  /* assumes a 0-byte memmove is OK */ -  memmove (&tree->subtrees[i], -           &tree->subtrees[i+1], -           (tree->n_subtrees - i - 1) * sizeof (tree->subtrees[0])); -  tree->n_subtrees -= 1; +  _dbus_assert (subtree->parent == NULL || +                (i >= 0 && subtree->parent->subtrees[i] == subtree));    subtree->message_function = NULL; -   + +  unregister_function = subtree->unregister_function; +  user_data = subtree->user_data; + +  subtree->unregister_function = NULL; +  subtree->user_data = NULL; + +  /* If we have no subtrees of our own, remove from +   * our parent (FIXME could also be more aggressive +   * and remove our parent if it becomes empty) +   */ +  if (subtree->parent && subtree->n_subtrees == 0) +    { +      /* assumes a 0-byte memmove is OK */ +      memmove (&subtree->parent->subtrees[i], +               &subtree->parent->subtrees[i+1], +               (subtree->parent->n_subtrees - i - 1) * +               sizeof (subtree->parent->subtrees[0])); +      subtree->parent->n_subtrees -= 1; + +      subtree->parent = NULL; + +      _dbus_object_subtree_unref (subtree); +    } +  subtree = NULL; + +  connection = tree->connection; +    /* Unlock and call application code */  #ifdef DBUS_BUILD_TESTS -  if (tree->connection) +  if (connection)  #endif -    _dbus_connection_unlock (tree->connection); -   +    { +      _dbus_connection_ref_unlocked (connection); +      _dbus_connection_unlock (connection); +    } + +  if (unregister_function) +    (* unregister_function) (connection, user_data); + +#ifdef DBUS_BUILD_TESTS +  if (connection) +#endif +    dbus_connection_unref (connection); +} + +static void +free_subtree_recurse (DBusConnection    *connection, +                      DBusObjectSubtree *subtree) +{ +  /* Delete them from the end, for slightly +   * more robustness against odd reentrancy. +   */ +  while (subtree->n_subtrees > 0) +    { +      DBusObjectSubtree *child; + +      child = subtree->subtrees[subtree->n_subtrees - 1]; +      subtree->subtrees[subtree->n_subtrees - 1] = NULL; +      subtree->n_subtrees -= 1; +      child->parent = NULL; + +      free_subtree_recurse (connection, child); +    } + +  /* Call application code */    if (subtree->unregister_function)      { -      (* subtree->unregister_function) (tree->connection, -                                        (const char**) subtree->path, +      (* subtree->unregister_function) (connection,                                          subtree->user_data); +      subtree->message_function = NULL;        subtree->unregister_function = NULL; +      subtree->user_data = NULL;      } +  /* Now free ourselves */    _dbus_object_subtree_unref (subtree);  } @@ -441,37 +490,15 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree          *tree,   * Free all the handlers in the tree. Lock on tree's connection   * must not be held.   * - * @todo implement - *    * @param tree the object tree   */  void  _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)  { -  /* Delete them from the end, for slightly -   * more robustness against odd reentrancy. -   */ -  while (tree->n_subtrees > 0) -    { -      DBusObjectSubtree *subtree; - -      subtree = tree->subtrees[tree->n_subtrees - 1]; -      tree->subtrees[tree->n_subtrees - 1] = NULL; -      tree->n_subtrees -= 1; - -      subtree->message_function = NULL; /* it's been removed */ - -      /* Call application code */ -      if (subtree->unregister_function) -        { -          (* subtree->unregister_function) (tree->connection, -                                            (const char**) subtree->path, -                                            subtree->user_data); -          subtree->unregister_function = NULL; -        } -       -      _dbus_object_subtree_unref (subtree);       -    } +  if (tree->root) +    free_subtree_recurse (tree->connection, +                          tree->root); +  tree->root = NULL;  }  /** @@ -482,7 +509,7 @@ _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)   * to the handler for /foo/bar before the one for /foo.   *   * @todo thread problems - *  + *   * @param tree the global object tree   * @param message the message to dispatch   * @returns whether message was handled successfully @@ -491,52 +518,82 @@ DBusHandlerResult  _dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,                                         DBusMessage             *message)  { -  const char **path; -  int i; +  char **path;    DBusList *list;    DBusList *link;    DBusHandlerResult result; +  DBusObjectSubtree *subtree; + +#if 0 +  _dbus_verbose ("Dispatch of message by object path\n"); +#endif -  path = NULL; /* dbus_message_get_object_path (message); */ +  path = NULL; +  if (!dbus_message_get_path_decomposed (message, &path)) +    { +      _dbus_verbose ("No memory to get decomposed path\n"); +      return DBUS_HANDLER_RESULT_NEED_MEMORY; +    }    if (path == NULL) -    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    { +      _dbus_verbose ("No path field in message\n"); +      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +    }    /* Find the deepest path that covers the path in the message */ -  if (!find_handler (tree, path, &i)) -    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +  subtree = find_handler (tree, (const char**) path);    /* Build a list of all paths that cover the path in the message */ -   +    list = NULL; -   -  do  -    { -      DBusObjectSubtree *subtree; -      subtree = tree->subtrees[i]; +  while (subtree != NULL) +    { +      if (subtree->message_function != NULL) +        { +          _dbus_object_subtree_ref (subtree); + +          /* run deepest paths first */ +          if (!_dbus_list_append (&list, subtree)) +            { +              result = DBUS_HANDLER_RESULT_NEED_MEMORY; +              _dbus_object_subtree_unref (subtree); +              goto free_and_return; +            } +        } -      _dbus_object_subtree_ref (subtree); -      _dbus_list_append (&list, subtree); +      subtree = subtree->parent; +    } -      --i; -       -    } while (i > 0 && path_contains ((const char**) tree->subtrees[i]->path, -                                     path)); +  _dbus_verbose ("%d handlers in the path tree for this message\n", +                 _dbus_list_get_length (&list));    /* Invoke each handler in the list */ -   +    result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -   +    link = _dbus_list_get_first_link (&list);    while (link != NULL)      { -      DBusObjectSubtree *subtree = link->data;        DBusList *next = _dbus_list_get_next_link (&list, link); -       -      /* message_function is NULL if we're unregistered */ +      subtree = link->data; + +      /* message_function is NULL if we're unregistered +       * due to reentrancy +       */        if (subtree->message_function)          { +          DBusObjectPathMessageFunction message_function; +          void *user_data; + +          message_function = subtree->message_function; +          user_data = subtree->user_data; + +#if 0 +          _dbus_verbose ("  (invoking a handler)\n"); +#endif +            #ifdef DBUS_BUILD_TESTS            if (tree->connection)  #endif @@ -546,19 +603,20 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,             * before we invoke the callback, and I can't figure out a             * good way to solve this.             */ -           -          result = (* subtree->message_function) (tree->connection, -                                                  message, subtree->user_data); -           -          if (result == DBUS_HANDLER_RESULT_HANDLED) + +          result = (* message_function) (tree->connection, +                                         message, +                                         user_data); + +          if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)              goto free_and_return;  #ifdef DBUS_BUILD_TESTS            if (tree->connection)  #endif              _dbus_connection_lock (tree->connection); -        }        -           +        } +        link = next;      } @@ -574,82 +632,69 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,        _dbus_object_subtree_unref (link->data);        _dbus_list_remove_link (&list, link);      } -   +  dbus_free_string_array (path); +    return result;  }  /** - * Allocates a subtree object with a string array appended as one big - * memory block, so result is freed with one dbus_free(). Returns - * #NULL if memory allocation fails. + * Allocates a subtree object.   * - * @param array array to duplicate. + * @param name name to duplicate.   * @returns newly-allocated subtree   */  static DBusObjectSubtree* -allocate_subtree_object (const char **array) +allocate_subtree_object (const char *name)  {    int len; -  int member_lens; -  int i; -  char *p; -  void *subtree; -  char **path_dest; -  const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, path); -   -  if (array == NULL) -    return NULL; +  DBusObjectSubtree *subtree; +  const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name); -  member_lens = 0; -  for (len = 0; array[len] != NULL; ++len) -    member_lens += strlen (array[len]) + 1; -   -  subtree = dbus_malloc (front_padding + -                         (len + 1) * sizeof (char*) + -                         member_lens); -  if (subtree == NULL) -    return NULL; +  _dbus_assert (name != NULL); -  path_dest = (char**) (((char*) subtree) + front_padding); -   -  path_dest[len] = NULL; /* NULL-terminate the array portion */ -  p = ((char*) subtree) + (len + 1) * sizeof (char*) + front_padding; -   -  i = 0; -  while (i < len) -    { -      int this_len; +  len = strlen (name); -      path_dest[i] = p; -       -      this_len = strlen (array[i]); -      memcpy (p, array[i], this_len + 1); -      p += this_len + 1; +  subtree = dbus_malloc (front_padding + (len + 1)); -      ++i; -    } +  if (subtree == NULL) +    return NULL; + +  memcpy (subtree->name, name, len + 1);    return subtree;  }  static DBusObjectSubtree* -_dbus_object_subtree_new (const char                 **path, +_dbus_object_subtree_new (const char                  *name,                            const DBusObjectPathVTable  *vtable,                            void                        *user_data)  {    DBusObjectSubtree *subtree; -  subtree = allocate_subtree_object (path); +  subtree = allocate_subtree_object (name);    if (subtree == NULL)      goto oom; -  _dbus_assert (path != NULL); -  _dbus_assert (path[0] != NULL); +  _dbus_assert (name != NULL); + +  subtree->parent = NULL; + +  if (vtable) +    { +      subtree->message_function = vtable->message_function; +      subtree->unregister_function = vtable->unregister_function; +    } +  else +    { +      subtree->message_function = NULL; +      subtree->unregister_function = NULL; +    } -  subtree->message_function = vtable->message_function; -  subtree->unregister_function = vtable->unregister_function;    subtree->user_data = user_data;    subtree->refcount.value = 1; +  subtree->subtrees = NULL; +  subtree->n_subtrees = 0; +  subtree->subtrees_sorted = TRUE;    return subtree; @@ -658,7 +703,7 @@ _dbus_object_subtree_new (const char                 **path,      {        dbus_free (subtree);      } -   +    return NULL;  } @@ -678,6 +723,8 @@ _dbus_object_subtree_unref (DBusObjectSubtree *subtree)      {        _dbus_assert (subtree->unregister_function == NULL);        _dbus_assert (subtree->message_function == NULL); + +      dbus_free (subtree->subtrees);        dbus_free (subtree);      }  } @@ -694,7 +741,7 @@ flatten_path (const char **path)    DBusString str;    int i;    char *s; -   +    if (!_dbus_string_init (&str))      return NULL; @@ -703,10 +750,10 @@ flatten_path (const char **path)      {        if (!_dbus_string_append_byte (&str, '/'))          goto nomem; -       +        if (!_dbus_string_append (&str, path[i]))          goto nomem; -       +        ++i;      } @@ -714,154 +761,89 @@ flatten_path (const char **path)      goto nomem;    _dbus_string_free (&str); -   +    return s; -   +   nomem:    _dbus_string_free (&str);    return NULL;  } -static void -spew_tree (DBusObjectTree *tree) +/* Returns TRUE if container is a parent of child + */ +static dbus_bool_t +path_contains (const char **container, +               const char **child)  {    int i; -  printf ("Tree of %d subpaths\n", -          tree->n_subtrees); -      i = 0; -  while (i < tree->n_subtrees) +  while (child[i] != NULL)      { -      char *s; - -      s = flatten_path ((const char **) tree->subtrees[i]->path); - -      printf ("  %d path = %s\n", i, s); - -      dbus_free (s); -       -      ++i; -    } -} - -static dbus_bool_t -test_subtree_cmp (const char **path1, -                  const char **path2, -                  int          expected, -                  dbus_bool_t  reverse) -{ -  DBusObjectSubtree *subtree1; -  DBusObjectSubtree *subtree2; -  dbus_bool_t retval; -  DBusObjectPathVTable vtable; - -  _DBUS_ZERO (vtable); - -  retval = FALSE; -   -  subtree1 = _dbus_object_subtree_new (path1, &vtable, NULL); -  subtree2 = _dbus_object_subtree_new (path2, &vtable, NULL); -  if (subtree1 == NULL || subtree2 == NULL) -    goto out; +      int v; -  _dbus_assert (subtree_cmp (subtree1, subtree2) == expected); +      if (container[i] == NULL) +        return TRUE; /* container ran out, child continues; +                      * thus the container is a parent of the +                      * child. +                      */ -  retval = TRUE; -   - out: +      _dbus_assert (container[i] != NULL); +      _dbus_assert (child[i] != NULL); -  if (subtree1) -    _dbus_object_subtree_unref (subtree1); +      v = strcmp (container[i], child[i]); -  if (subtree2) -    _dbus_object_subtree_unref (subtree2); +      if (v != 0) +        return FALSE; /* they overlap until here and then are different, +                       * not overlapping +                       */ -  if (retval && reverse) -    { -      /* Verify that the reverse also holds */ -      if (expected > 0) -        return test_subtree_cmp (path2, path1, -1, FALSE); -      else if (expected < 0) -        return test_subtree_cmp (path2, path1, 1, FALSE); -      else -        return test_subtree_cmp (path2, path1, 0, FALSE); +      ++i;      } -   -  return retval; + +  /* Child ran out; if container also did, they are equal; +   * otherwise, the child is a parent of the container. +   */ +  if (container[i] == NULL) +    return TRUE; /* equal is counted as containing */ +  else +    return FALSE;  }  static void -test_path_contains (const char  **path1, -                    const char  **path2, -                    dbus_bool_t   expected) +spew_subtree_recurse (DBusObjectSubtree *subtree, +                      int                indent)  { -  if (!path_contains (path1, path2) == expected) -    { -      char *s1, *s2; -      s1 = flatten_path (path1); -      s2 = flatten_path (path2); -       -      _dbus_warn ("Expected that path %s %s %s\n", -                  s1, expected ? "contains" : "doesn't contain", s2); -       -      dbus_free (s1); -      dbus_free (s2); -       -      exit (1); -    } -   -  if (path_cmp (path1, path2) == 0) +  int i; + +  i = 0; +  while (i < indent)      { -      if (!path_contains (path2, path1)) -        { -          char *s1, *s2; -          s1 = flatten_path (path1); -          s2 = flatten_path (path2); -           -          _dbus_warn ("Expected that path %s contains %s since the paths are equal\n", -                      s1, s2); -           -          dbus_free (s1); -          dbus_free (s2); -           -          exit (1); -        } +      _dbus_verbose (" "); +      ++i;      } -  /* If path1 contains path2, then path2 can't contain path1 */ -  else if (expected && path_contains (path2, path1)) -    { -      char *s1, *s2; -      s1 = flatten_path (path1); -      s2 = flatten_path (path2); -       -      _dbus_warn ("Expected that path %s doesn't contain %s\n", -                  s1, s2); +  _dbus_verbose ("%s (%d children)\n", +                 subtree->name, subtree->n_subtrees); -      dbus_free (s1); -      dbus_free (s2); -       -      exit (1); +  i = 0; +  while (i < subtree->n_subtrees) +    { +      spew_subtree_recurse (subtree->subtrees[i], indent + 2); + +      ++i;      }  }  static void -test_path_copy (const char **path) +spew_tree (DBusObjectTree *tree)  { -  DBusObjectSubtree *subtree; - -  subtree = allocate_subtree_object (path); -  if (subtree == NULL) -    return; -   -  _dbus_assert (path_cmp (path, (const char**) subtree->path) == 0); - -  dbus_free (subtree); +  spew_subtree_recurse (tree->root, 0);  }  typedef struct  { +  const char **path;    dbus_bool_t message_handled;    dbus_bool_t handler_unregistered; @@ -870,7 +852,6 @@ typedef struct  static void  test_unregister_function (DBusConnection  *connection, -                          const char     **path,                            void            *user_data)  {    TreeTestData *ttd = user_data; @@ -886,7 +867,7 @@ test_message_function (DBusConnection  *connection,    TreeTestData *ttd = user_data;    ttd->message_handled = TRUE; -   +    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;  } @@ -901,7 +882,8 @@ do_register (DBusObjectTree *tree,    tree_test_data[i].message_handled = FALSE;    tree_test_data[i].handler_unregistered = FALSE; -   +  tree_test_data[i].path = path; +    if (!_dbus_object_tree_register (tree, path,                                     &vtable,                                     &tree_test_data[i])) @@ -911,6 +893,68 @@ do_register (DBusObjectTree *tree,  }  static dbus_bool_t +do_test_dispatch (DBusObjectTree *tree, +                  const char    **path, +                  int             i, +                  TreeTestData   *tree_test_data, +                  int             n_test_data) +{ +  DBusMessage *message; +  int j; +  DBusHandlerResult result; +  char *flat; + +  message = NULL; +   +  flat = flatten_path (path); +  if (flat == NULL) +    goto oom; + +  message = dbus_message_new_method_call (NULL, +                                          flat, +                                          "org.freedesktop.TestInterface", +                                          "Foo"); +  dbus_free (flat); +  if (message == NULL) +    goto oom; + +  j = 0; +  while (j < n_test_data) +    { +      tree_test_data[j].message_handled = FALSE; +      ++j; +    } + +  result = _dbus_object_tree_dispatch_and_unlock (tree, message); +  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) +    goto oom; + +  _dbus_assert (tree_test_data[i].message_handled); + +  j = 0; +  while (j < n_test_data) +    { +      if (tree_test_data[j].message_handled) +        _dbus_assert (path_contains (tree_test_data[j].path, +                                     path)); +      else +        _dbus_assert (!path_contains (tree_test_data[j].path, +                                      path)); + +      ++j; +    } + +  dbus_message_unref (message); + +  return TRUE; + + oom: +  if (message) +    dbus_message_unref (message); +  return FALSE; +} + +static dbus_bool_t  object_tree_test_iteration (void *data)  {    const char *path1[] = { "foo", NULL }; @@ -919,103 +963,51 @@ object_tree_test_iteration (void *data)    const char *path4[] = { "foo", "bar", "boo", NULL };    const char *path5[] = { "blah", NULL };    const char *path6[] = { "blah", "boof", NULL }; +  const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; +  const char *path8[] = { "childless", NULL };    DBusObjectTree *tree; -  TreeTestData tree_test_data[6]; +  TreeTestData tree_test_data[8];    int i; -   -  test_path_copy (path1); -  test_path_copy (path2); -  test_path_copy (path3); -  test_path_copy (path4); -  test_path_copy (path5); -  test_path_copy (path6); -   +    tree = NULL; -  test_path_contains (path1, path1, TRUE); -  test_path_contains (path1, path2, TRUE); -  test_path_contains (path1, path3, TRUE); -  test_path_contains (path1, path4, TRUE); -  test_path_contains (path1, path5, FALSE); -  test_path_contains (path1, path6, FALSE);  - -  test_path_contains (path2, path1, FALSE); -  test_path_contains (path2, path2, TRUE); -  test_path_contains (path2, path3, TRUE); -  test_path_contains (path2, path4, TRUE); -  test_path_contains (path2, path5, FALSE); -  test_path_contains (path2, path6, FALSE); - -  test_path_contains (path3, path1, FALSE); -  test_path_contains (path3, path2, FALSE); -  test_path_contains (path3, path3, TRUE); -  test_path_contains (path3, path4, FALSE); -  test_path_contains (path3, path5, FALSE); -  test_path_contains (path3, path6, FALSE); - -  test_path_contains (path4, path1, FALSE); -  test_path_contains (path4, path2, FALSE); -  test_path_contains (path4, path3, FALSE); -  test_path_contains (path4, path4, TRUE); -  test_path_contains (path4, path5, FALSE); -  test_path_contains (path4, path6, FALSE); - -  test_path_contains (path5, path1, FALSE); -  test_path_contains (path5, path2, FALSE); -  test_path_contains (path5, path3, FALSE); -  test_path_contains (path5, path4, FALSE); -  test_path_contains (path5, path5, TRUE); -  test_path_contains (path5, path6, TRUE); -   -  test_path_contains (path6, path1, FALSE); -  test_path_contains (path6, path2, FALSE); -  test_path_contains (path6, path3, FALSE); -  test_path_contains (path6, path4, FALSE); -  test_path_contains (path6, path5, FALSE); -  test_path_contains (path6, path6, TRUE); -   -  if (!test_subtree_cmp (path1, path1, 0, TRUE)) -    goto out; -  if (!test_subtree_cmp (path3, path3, 0, TRUE)) -    goto out; -  /* When testing -1, the reverse also gets tested */ -  if (!test_subtree_cmp (path1, path2, -1, TRUE)) -    goto out; -  if (!test_subtree_cmp (path1, path3, -1, TRUE)) -    goto out; -  if (!test_subtree_cmp (path2, path3, -1, TRUE)) -    goto out; -  if (!test_subtree_cmp (path2, path4, -1, TRUE)) -    goto out; -  if (!test_subtree_cmp (path3, path4, -1, TRUE)) -    goto out; -  if (!test_subtree_cmp (path5, path1, -1, TRUE)) -    goto out; -      tree = _dbus_object_tree_new (NULL);    if (tree == NULL)      goto out; -   +    if (!do_register (tree, path1, 0, tree_test_data))      goto out; -   +    _dbus_assert (find_subtree (tree, path1, NULL));    _dbus_assert (!find_subtree (tree, path2, NULL));    _dbus_assert (!find_subtree (tree, path3, NULL));    _dbus_assert (!find_subtree (tree, path4, NULL));    _dbus_assert (!find_subtree (tree, path5, NULL));    _dbus_assert (!find_subtree (tree, path6, NULL)); -   +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL)); + +  _dbus_assert (find_handler (tree, path1)); +  _dbus_assert (find_handler (tree, path2)); +  _dbus_assert (find_handler (tree, path3)); +  _dbus_assert (find_handler (tree, path4)); +  _dbus_assert (find_handler (tree, path5) == tree->root); +  _dbus_assert (find_handler (tree, path6) == tree->root); +  _dbus_assert (find_handler (tree, path7) == tree->root); +  _dbus_assert (find_handler (tree, path8) == tree->root); +    if (!do_register (tree, path2, 1, tree_test_data))      goto out; -   -  _dbus_assert (find_subtree (tree, path1, NULL));   + +  _dbus_assert (find_subtree (tree, path1, NULL));    _dbus_assert (find_subtree (tree, path2, NULL));    _dbus_assert (!find_subtree (tree, path3, NULL));    _dbus_assert (!find_subtree (tree, path4, NULL));    _dbus_assert (!find_subtree (tree, path5, NULL));    _dbus_assert (!find_subtree (tree, path6, NULL)); -   +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL)); +    if (!do_register (tree, path3, 2, tree_test_data))      goto out; @@ -1025,17 +1017,20 @@ object_tree_test_iteration (void *data)    _dbus_assert (!find_subtree (tree, path4, NULL));    _dbus_assert (!find_subtree (tree, path5, NULL));    _dbus_assert (!find_subtree (tree, path6, NULL)); +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL));    if (!do_register (tree, path4, 3, tree_test_data))      goto out; -    _dbus_assert (find_subtree (tree, path1, NULL));    _dbus_assert (find_subtree (tree, path2, NULL)); -  _dbus_assert (find_subtree (tree, path3, NULL)); +  _dbus_assert (find_subtree (tree, path3, NULL));      _dbus_assert (find_subtree (tree, path4, NULL));    _dbus_assert (!find_subtree (tree, path5, NULL));    _dbus_assert (!find_subtree (tree, path6, NULL)); +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL));    if (!do_register (tree, path5, 4, tree_test_data))      goto out; @@ -1046,7 +1041,18 @@ object_tree_test_iteration (void *data)    _dbus_assert (find_subtree (tree, path4, NULL));    _dbus_assert (find_subtree (tree, path5, NULL));    _dbus_assert (!find_subtree (tree, path6, NULL)); +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL)); +  _dbus_assert (find_handler (tree, path1) != tree->root); +  _dbus_assert (find_handler (tree, path2) != tree->root); +  _dbus_assert (find_handler (tree, path3) != tree->root); +  _dbus_assert (find_handler (tree, path4) != tree->root); +  _dbus_assert (find_handler (tree, path5) != tree->root); +  _dbus_assert (find_handler (tree, path6) != tree->root); +  _dbus_assert (find_handler (tree, path7) != tree->root); +  _dbus_assert (find_handler (tree, path8) == tree->root); +    if (!do_register (tree, path6, 5, tree_test_data))      goto out; @@ -1056,7 +1062,42 @@ object_tree_test_iteration (void *data)    _dbus_assert (find_subtree (tree, path4, NULL));    _dbus_assert (find_subtree (tree, path5, NULL));    _dbus_assert (find_subtree (tree, path6, NULL)); +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL)); + +  if (!do_register (tree, path7, 6, tree_test_data)) +    goto out; +  _dbus_assert (find_subtree (tree, path1, NULL)); +  _dbus_assert (find_subtree (tree, path2, NULL)); +  _dbus_assert (find_subtree (tree, path3, NULL)); +  _dbus_assert (find_subtree (tree, path4, NULL)); +  _dbus_assert (find_subtree (tree, path5, NULL)); +  _dbus_assert (find_subtree (tree, path6, NULL)); +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL)); + +  if (!do_register (tree, path8, 7, tree_test_data)) +    goto out; + +  _dbus_assert (find_subtree (tree, path1, NULL)); +  _dbus_assert (find_subtree (tree, path2, NULL)); +  _dbus_assert (find_subtree (tree, path3, NULL)); +  _dbus_assert (find_subtree (tree, path4, NULL)); +  _dbus_assert (find_subtree (tree, path5, NULL)); +  _dbus_assert (find_subtree (tree, path6, NULL)); +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL)); +   +  _dbus_assert (find_handler (tree, path1) != tree->root); +  _dbus_assert (find_handler (tree, path2) != tree->root); +  _dbus_assert (find_handler (tree, path3) != tree->root); +  _dbus_assert (find_handler (tree, path4) != tree->root); +  _dbus_assert (find_handler (tree, path5) != tree->root); +  _dbus_assert (find_handler (tree, path6) != tree->root); +  _dbus_assert (find_handler (tree, path7) != tree->root); +  _dbus_assert (find_handler (tree, path8) != tree->root); +      /* Check that destroying tree calls unregister funcs */    _dbus_object_tree_unref (tree); @@ -1072,7 +1113,7 @@ object_tree_test_iteration (void *data)    tree = _dbus_object_tree_new (NULL);    if (tree == NULL)      goto out; -   +    if (!do_register (tree, path1, 0, tree_test_data))      goto out;    if (!do_register (tree, path2, 1, tree_test_data)) @@ -1085,7 +1126,11 @@ object_tree_test_iteration (void *data)      goto out;    if (!do_register (tree, path6, 5, tree_test_data))      goto out; - +  if (!do_register (tree, path7, 6, tree_test_data)) +    goto out; +  if (!do_register (tree, path8, 7, tree_test_data)) +    goto out; +      _dbus_object_tree_unregister_and_unlock (tree, path1);    _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1094,7 +1139,9 @@ object_tree_test_iteration (void *data)    _dbus_assert (find_subtree (tree, path4, NULL));    _dbus_assert (find_subtree (tree, path5, NULL));    _dbus_assert (find_subtree (tree, path6, NULL)); -   +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL)); +    _dbus_object_tree_unregister_and_unlock (tree, path2);    _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1103,7 +1150,9 @@ object_tree_test_iteration (void *data)    _dbus_assert (find_subtree (tree, path4, NULL));    _dbus_assert (find_subtree (tree, path5, NULL));    _dbus_assert (find_subtree (tree, path6, NULL)); - +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL)); +      _dbus_object_tree_unregister_and_unlock (tree, path3);    _dbus_assert (!find_subtree (tree, path1, NULL)); @@ -1112,6 +1161,8 @@ object_tree_test_iteration (void *data)    _dbus_assert (find_subtree (tree, path4, NULL));    _dbus_assert (find_subtree (tree, path5, NULL));    _dbus_assert (find_subtree (tree, path6, NULL)); +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL));    _dbus_object_tree_unregister_and_unlock (tree, path4); @@ -1121,6 +1172,8 @@ object_tree_test_iteration (void *data)    _dbus_assert (!find_subtree (tree, path4, NULL));    _dbus_assert (find_subtree (tree, path5, NULL));    _dbus_assert (find_subtree (tree, path6, NULL)); +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL));    _dbus_object_tree_unregister_and_unlock (tree, path5); @@ -1130,6 +1183,8 @@ object_tree_test_iteration (void *data)    _dbus_assert (!find_subtree (tree, path4, NULL));    _dbus_assert (!find_subtree (tree, path5, NULL));    _dbus_assert (find_subtree (tree, path6, NULL)); +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL));    _dbus_object_tree_unregister_and_unlock (tree, path6); @@ -1139,6 +1194,30 @@ object_tree_test_iteration (void *data)    _dbus_assert (!find_subtree (tree, path4, NULL));    _dbus_assert (!find_subtree (tree, path5, NULL));    _dbus_assert (!find_subtree (tree, path6, NULL)); +  _dbus_assert (find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL)); + +  _dbus_object_tree_unregister_and_unlock (tree, path7); + +  _dbus_assert (!find_subtree (tree, path1, NULL)); +  _dbus_assert (!find_subtree (tree, path2, NULL)); +  _dbus_assert (!find_subtree (tree, path3, NULL)); +  _dbus_assert (!find_subtree (tree, path4, NULL)); +  _dbus_assert (!find_subtree (tree, path5, NULL)); +  _dbus_assert (!find_subtree (tree, path6, NULL)); +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (find_subtree (tree, path8, NULL)); + +  _dbus_object_tree_unregister_and_unlock (tree, path8); + +  _dbus_assert (!find_subtree (tree, path1, NULL)); +  _dbus_assert (!find_subtree (tree, path2, NULL)); +  _dbus_assert (!find_subtree (tree, path3, NULL)); +  _dbus_assert (!find_subtree (tree, path4, NULL)); +  _dbus_assert (!find_subtree (tree, path5, NULL)); +  _dbus_assert (!find_subtree (tree, path6, NULL)); +  _dbus_assert (!find_subtree (tree, path7, NULL)); +  _dbus_assert (!find_subtree (tree, path8, NULL));    i = 0;    while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) @@ -1149,7 +1228,7 @@ object_tree_test_iteration (void *data)      }    /* Register it all again, and test dispatch */ -   +    if (!do_register (tree, path1, 0, tree_test_data))      goto out;    if (!do_register (tree, path2, 1, tree_test_data)) @@ -1162,13 +1241,36 @@ object_tree_test_iteration (void *data)      goto out;    if (!do_register (tree, path6, 5, tree_test_data))      goto out; +  if (!do_register (tree, path7, 6, tree_test_data)) +    goto out; +  if (!do_register (tree, path8, 7, tree_test_data)) +    goto out; + +#if 0 +  spew_tree (tree); +#endif -  /* FIXME (once messages have an object path field) */ +  if (!do_test_dispatch (tree, path1, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out; +  if (!do_test_dispatch (tree, path2, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out; +  if (!do_test_dispatch (tree, path3, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out; +  if (!do_test_dispatch (tree, path4, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out; +  if (!do_test_dispatch (tree, path5, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out; +  if (!do_test_dispatch (tree, path6, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out; +  if (!do_test_dispatch (tree, path7, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out; +  if (!do_test_dispatch (tree, path8, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) +    goto out;   out:    if (tree)      _dbus_object_tree_unref (tree); -   +    return TRUE;  } @@ -1183,7 +1285,7 @@ _dbus_object_tree_test (void)    _dbus_test_oom_handling ("object tree",                             object_tree_test_iteration,                             NULL); -   +    return TRUE;  } diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index a23d7466..e56ab756 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -71,17 +71,22 @@ extern "C" {  #define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1  /* Header fields */ -#define DBUS_HEADER_FIELD_INTERFACE  "ifce" -#define DBUS_HEADER_FIELD_MEMBER     "mebr" -#define DBUS_HEADER_FIELD_ERROR_NAME "ernm" -#define DBUS_HEADER_FIELD_SERVICE    "srvc" -#define DBUS_HEADER_FIELD_REPLY	     "rply" -#define DBUS_HEADER_FIELD_SENDER     "sndr" +#define DBUS_HEADER_FIELD_PATH           "path" +#define DBUS_HEADER_FIELD_INTERFACE      "ifce" +#define DBUS_HEADER_FIELD_MEMBER         "mebr" +#define DBUS_HEADER_FIELD_ERROR_NAME     "ernm" +#define DBUS_HEADER_FIELD_SERVICE        "srvc" +#define DBUS_HEADER_FIELD_REPLY	         "rply" +#define DBUS_HEADER_FIELD_SENDER_SERVICE "sdrs"  /* Services */  #define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS      "org.freedesktop.DBus"  #define DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST "org.freedesktop.Broadcast" +/* Paths */ +#define DBUS_PATH_ORG_FREEDESKTOP_DBUS  "/org/freedesktop/DBus" +#define DBUS_PATH_ORG_FREEDESKTOP_LOCAL "/org/freedesktop/Local" +    /* Service owner flags */  #define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1  #define DBUS_SERVICE_FLAG_REPLACE_EXISTING     0x2 diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 75b38b9d..54dbdb7f 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -2846,6 +2846,74 @@ _dbus_string_validate_nul (const DBusString *str,  }  /** + * Checks that the given range of the string is a valid object path + * name in the D-BUS protocol. This includes a length restriction, + * etc., see the specification. It does not validate UTF-8, that has + * to be done separately for now. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that isn't in the string. + * + * @todo change spec to disallow more things, such as spaces in the + * path name + *  + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_string_validate_path (const DBusString  *str, +                            int                start, +                            int                len) +{ +  const unsigned char *s; +  const unsigned char *end; +  const unsigned char *last_slash; +   +  DBUS_CONST_STRING_PREAMBLE (str); +  _dbus_assert (start >= 0); +  _dbus_assert (len >= 0); +  _dbus_assert (start <= real->len); +   +  if (len > real->len - start) +    return FALSE; + +  if (len > DBUS_MAXIMUM_NAME_LENGTH) +    return FALSE; + +  if (len == 0) +    return FALSE; + +  s = real->str + start; +  end = s + len; + +  if (*s != '/') +    return FALSE; +  last_slash = s; +  ++s; +   +  while (s != end) +    { +      if (*s == '/') +        { +          if ((s - last_slash) < 2) +            return FALSE; /* no empty path components allowed */ + +          last_slash = s; +        } +       +      ++s; +    } + +  if ((end - last_slash) < 2 && +      len > 1) +    return FALSE; /* trailing slash not allowed unless the string is "/" */ +   +  return TRUE; +} + +/**   * Checks that the given range of the string is a valid interface name   * in the D-BUS protocol. This includes a length restriction, etc.,   * see the specification. It does not validate UTF-8, that has to be @@ -3251,6 +3319,24 @@ _dbus_string_test (void)    int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };    char *s;    dbus_unichar_t ch; +  const char *valid_paths[] = { +    "/", +    "/foo/bar", +    "/foo", +    "/foo/bar/baz" +  }; +  const char *invalid_paths[] = { +    "bar", +    "bar/baz", +    "/foo/bar/", +    "/foo/" +    "foo/", +    "boo//blah", +    "//", +    "///", +    "foo///blah/", +    "Hello World" +  };    i = 0;    while (i < _DBUS_N_ELEMENTS (lens)) @@ -3625,7 +3711,38 @@ _dbus_string_test (void)    /* Base 64 and Hex encoding */    test_roundtrips (test_base64_roundtrip);    test_roundtrips (test_hex_roundtrip); -   + +  /* Path validation */ +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (valid_paths)) +    { +      _dbus_string_init_const (&str, valid_paths[i]); + +      if (!_dbus_string_validate_path (&str, 0, +                                       _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]); +          _dbus_assert_not_reached ("invalid path"); +        } +       +      ++i; +    } + +  i = 0; +  while (i < (int) _DBUS_N_ELEMENTS (invalid_paths)) +    { +      _dbus_string_init_const (&str, invalid_paths[i]); +       +      if (_dbus_string_validate_path (&str, 0, +                                      _dbus_string_get_length (&str))) +        { +          _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]); +          _dbus_assert_not_reached ("valid path"); +        } +       +      ++i; +    } +             return TRUE;  } diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 6f164be6..761ad487 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -223,6 +223,9 @@ dbus_bool_t   _dbus_string_validate_utf8         (const DBusString  *str,  dbus_bool_t   _dbus_string_validate_nul          (const DBusString  *str,                                                    int                start,                                                    int                len); +dbus_bool_t   _dbus_string_validate_path         (const DBusString  *str, +                                                  int                start, +                                                  int                len);  dbus_bool_t   _dbus_string_validate_interface    (const DBusString  *str,                                                    int                start,                                                    int                len); diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 259244ce..774a3138 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -81,7 +81,7 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)      die ("strings");    check_memleaks (); - +      printf ("%s: running sysdeps tests\n", "dbus-test");    if (!_dbus_sysdeps_test ())      die ("sysdeps"); @@ -76,3 +76,6 @@     really see how to do this without making the user pass around the     call serial to all method calls all the time, or disallowing      async calls. + + - the invalid messages in the test suite are all useless because  +   they are invalid for the wrong reasons due to protocol changes diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index c1a1f6dc..d64e95a7 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -197,12 +197,6 @@ method_info_get_args (MethodInfo *info)    return info->args;  } -MethodStyle -method_info_get_style (MethodInfo *info) -{ -  return info->style; -} -  void  method_info_add_arg (MethodInfo    *info,                       ArgInfo       *arg) diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 812e1866..68649cf3 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -56,7 +56,6 @@ void           method_info_unref          (MethodInfo    *info);  const char*    method_info_get_name       (MethodInfo    *info);  GSList*        method_info_get_args       (MethodInfo    *info); -MethodStyle    method_info_get_style      (MethodInfo    *info);  void           method_info_add_arg        (MethodInfo    *info,                                             ArgInfo       *arg); diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c index 6b057078..beda0a7a 100644 --- a/glib/test-dbus-glib.c +++ b/glib/test-dbus-glib.c @@ -30,9 +30,10 @@ main (int argc, char **argv)    dbus_connection_setup_with_g_main (connection, NULL); -  message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, -                                          "Hello", -                                          DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); +  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, +                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS, +                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, +                                          "Hello");    dbus_error_init (&error);    reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); diff --git a/glib/test-profile.c b/glib/test-profile.c index bd04dd9c..3eac1618 100644 --- a/glib/test-profile.c +++ b/glib/test-profile.c @@ -34,7 +34,8 @@  #define N_CLIENT_THREADS 1  #define N_ITERATIONS 1000  #define PAYLOAD_SIZE 30 -#define ECHO_INTERFACE "org.freedekstop.EchoTest" +#define ECHO_PATH "/org/freedesktop/EchoTest" +#define ECHO_INTERFACE "org.freedesktop.EchoTest"  #define ECHO_METHOD "EchoProfile"  static const char *address; @@ -45,7 +46,8 @@ send_echo_message (DBusConnection *connection)  {    DBusMessage *message; -  message = dbus_message_new_method_call (ECHO_INTERFACE, ECHO_METHOD, NULL); +  message = dbus_message_new_method_call (NULL, ECHO_PATH, +                                          ECHO_INTERFACE, ECHO_METHOD);    dbus_message_append_args (message,                              DBUS_TYPE_STRING, "Hello World!",                              DBUS_TYPE_INT32, 123456, diff --git a/glib/test-thread-client.c b/glib/test-thread-client.c index 8a1e44cb..d51d4e6a 100644 --- a/glib/test-thread-client.c +++ b/glib/test-thread-client.c @@ -19,8 +19,10 @@ thread_func (gpointer data)    while (1)      { -      message = dbus_message_new_method_call ("org.freedesktop.ThreadTest", -                                              "TestMethod", NULL); +      message = dbus_message_new_method_call (NULL, +                                              "/org/freedesktop/ThreadTest", +                                              "org.freedesktop.ThreadTest", +                                              "TestMethod");        dbus_message_append_iter_init (message, &iter); diff --git a/test/data/valid-config-files/system.d/test.conf b/test/data/valid-config-files/system.d/test.conf index 3d1b2f54..10a79847 100644 --- a/test/data/valid-config-files/system.d/test.conf +++ b/test/data/valid-config-files/system.d/test.conf @@ -5,9 +5,9 @@         policy so that a particular user can own a service, and other          connections can get messages from it --> -  <!-- Only fooserviceuser can own the FooService service, and  +  <!-- Only root can own the FooService service, and          this user can only send the one kind of message --> -  <policy user="fooserviceuser"> +  <policy user="root">      <allow own="org.foo.FooService"/>      <allow send_interface="org.foo.FooBroadcastInterface"/>    </policy> diff --git a/test/data/valid-messages/array-of-array-of-uint32.message b/test/data/valid-messages/array-of-array-of-uint32.message index 4fea3d25..692eca06 100644 --- a/test/data/valid-messages/array-of-array-of-uint32.message +++ b/test/data/valid-messages/array-of-array-of-uint32.message @@ -1,12 +1,7 @@  # Message with an array of array of uint32  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  END_LENGTH Header  ALIGN 8  START_LENGTH Body diff --git a/test/data/valid-messages/dict-simple.message b/test/data/valid-messages/dict-simple.message index 9450ef14..6986d439 100644 --- a/test/data/valid-messages/dict-simple.message +++ b/test/data/valid-messages/dict-simple.message @@ -1,12 +1,7 @@  # A simple dict  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  END_LENGTH Header  ALIGN 8  START_LENGTH Body diff --git a/test/data/valid-messages/dict.message b/test/data/valid-messages/dict.message index 6b15c627..0f997b1f 100644 --- a/test/data/valid-messages/dict.message +++ b/test/data/valid-messages/dict.message @@ -1,12 +1,7 @@  # Dict with different values  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  ALIGN 8  END_LENGTH Header  START_LENGTH Body diff --git a/test/data/valid-messages/emptiness.message b/test/data/valid-messages/emptiness.message index edc7a6cb..dbf531ca 100644 --- a/test/data/valid-messages/emptiness.message +++ b/test/data/valid-messages/emptiness.message @@ -1,12 +1,7 @@  # Empty arrays and strings  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  END_LENGTH Header  ALIGN 8  START_LENGTH Body diff --git a/test/data/valid-messages/lots-of-arguments.message b/test/data/valid-messages/lots-of-arguments.message index 36cad4cd..993755ab 100644 --- a/test/data/valid-messages/lots-of-arguments.message +++ b/test/data/valid-messages/lots-of-arguments.message @@ -1,12 +1,7 @@  # Message with lots of different argument types  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  END_LENGTH Header  ALIGN 8  START_LENGTH Body diff --git a/test/data/valid-messages/no-padding.message b/test/data/valid-messages/no-padding.message index 0241c364..e6d27d9d 100644 --- a/test/data/valid-messages/no-padding.message +++ b/test/data/valid-messages/no-padding.message @@ -3,12 +3,7 @@  ## VALID_HEADER includes a LENGTH Header and LENGTH Body  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  ## this byte array is filled with zeros to the natural length   ## of the header diff --git a/test/data/valid-messages/opposite-endian.message b/test/data/valid-messages/opposite-endian.message index b225f013..c638b7b0 100644 --- a/test/data/valid-messages/opposite-endian.message +++ b/test/data/valid-messages/opposite-endian.message @@ -5,12 +5,7 @@ OPPOSITE_ENDIAN  ## VALID_HEADER includes a LENGTH Header and LENGTH Body  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  FIELD_NAME unkn  TYPE INT32 diff --git a/test/data/valid-messages/recursive-types.message b/test/data/valid-messages/recursive-types.message index a8ef0441..192fd9b7 100644 --- a/test/data/valid-messages/recursive-types.message +++ b/test/data/valid-messages/recursive-types.message @@ -3,12 +3,7 @@  ## VALID_HEADER includes a LENGTH Header and LENGTH Body  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  END_LENGTH Header  START_LENGTH Body diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message index 533c1179..9779234b 100644 --- a/test/data/valid-messages/simplest-manual.message +++ b/test/data/valid-messages/simplest-manual.message @@ -11,6 +11,9 @@ LENGTH Body  ## client serial  INT32 7 +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/foo'  FIELD_NAME ifce  TYPE STRING  STRING 'org.freedesktop.Foo' diff --git a/test/data/valid-messages/simplest.message b/test/data/valid-messages/simplest.message index 868d270e..b9ddaf6b 100644 --- a/test/data/valid-messages/simplest.message +++ b/test/data/valid-messages/simplest.message @@ -2,13 +2,7 @@  ## VALID_HEADER includes a LENGTH Header and LENGTH Body  VALID_HEADER method_call - -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  ALIGN 8  END_LENGTH Header diff --git a/test/data/valid-messages/standard-acquire-service.message b/test/data/valid-messages/standard-acquire-service.message index 081473f0..f313061f 100644 --- a/test/data/valid-messages/standard-acquire-service.message +++ b/test/data/valid-messages/standard-acquire-service.message @@ -1,6 +1,9 @@  # Standard org.freedesktop.DBus.AcquireService message  VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus'  FIELD_NAME ifce  TYPE STRING  STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-hello.message b/test/data/valid-messages/standard-hello.message index ed9ff9e7..795ede74 100644 --- a/test/data/valid-messages/standard-hello.message +++ b/test/data/valid-messages/standard-hello.message @@ -1,6 +1,9 @@  # Standard org.freedesktop.DBus.Hello message  VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus'  FIELD_NAME ifce  TYPE STRING  STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-list-services.message b/test/data/valid-messages/standard-list-services.message index 9a6f1d87..4c9c7c66 100644 --- a/test/data/valid-messages/standard-list-services.message +++ b/test/data/valid-messages/standard-list-services.message @@ -1,6 +1,9 @@  # Standard org.freedesktop.DBus.ListServices message  VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus'  FIELD_NAME ifce  TYPE STRING  STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-service-exists.message b/test/data/valid-messages/standard-service-exists.message index c53319b6..ce14811a 100644 --- a/test/data/valid-messages/standard-service-exists.message +++ b/test/data/valid-messages/standard-service-exists.message @@ -1,6 +1,9 @@  # Standard org.freedesktop.DBus.ServiceExists message  VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus'  FIELD_NAME ifce  TYPE STRING  STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/unknown-header-field.message b/test/data/valid-messages/unknown-header-field.message index 17ae116a..5d95f812 100644 --- a/test/data/valid-messages/unknown-header-field.message +++ b/test/data/valid-messages/unknown-header-field.message @@ -2,12 +2,7 @@  ## VALID_HEADER includes a LENGTH Header and LENGTH Body  VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS  FIELD_NAME unkn  TYPE INT32  INT32 0xfeeb diff --git a/tools/dbus-send.1 b/tools/dbus-send.1 index 978ee2e7..725507c0 100644 --- a/tools/dbus-send.1 +++ b/tools/dbus-send.1 @@ -8,7 +8,8 @@ dbus-send \- Send a message to a message bus  .SH SYNOPSIS  .PP  .B dbus-send -[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply] [\-\-type=TYPE] <message name> [contents ...] +[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply] +[\-\-type=TYPE] <destination object path> <message name> [contents ...]  .SH DESCRIPTION @@ -28,21 +29,22 @@ specified, \fIdbus-send\fP sends to the session bus.  Nearly all uses of \fIdbus-send\fP must provide the \-\-dest argument  which is the name of a service on the bus to send the message to. If  \-\-dest is omitted, a default service name of -"org.freedesktop.DBus.Broadcast" is used.   +"org.freedesktop.Broadcast" is used.    .PP -The name of the message to send must always be specified. Following -arguments, if any, are the message contents (message arguments). -These are given as a type name, a colon, and then the value of the -argument. The possible type names are: string, int32, uint32, double, -byte, boolean.  (D-BUS supports more types than these, but -\fIdbus-send\fP currently does not.) +The object path and the name of the message to send must always be +specified. Following arguments, if any, are the message contents +(message arguments).  These are given as a type name, a colon, and +then the value of the argument. The possible type names are: string, +int32, uint32, double, byte, boolean.  (D-BUS supports more types than +these, but \fIdbus-send\fP currently does not.)  .PP  Here is an example invocation:  .nf    dbus-send \-\-dest='org.freedesktop.ExampleService'        \\ +            /org/freedesktop/sample/object/name              \\              org.freedesktop.ExampleInterface.ExampleMethod   \\              int32:47 string:'hello world' double:65.32 diff --git a/tools/dbus-send.c b/tools/dbus-send.c index 7ea49aac..67abe066 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -30,7 +30,7 @@  static void  usage (char *name, int ecode)  { -  fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--type=TYPE] [--print-reply] <message name> [contents ...]\n", name); +  fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--type=TYPE] [--print-reply] <destination object path> <message name> [contents ...]\n", name);    exit (ecode);  } @@ -45,11 +45,12 @@ main (int argc, char *argv[])    int i;    DBusBusType type = DBUS_BUS_SESSION;    const char *dest = DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST; -  char *name = NULL; +  const char *name = NULL; +  const char *path = NULL;    int message_type = DBUS_MESSAGE_TYPE_SIGNAL;    const char *type_str = NULL; -  if (argc < 2) +  if (argc < 3)      usage (argv[0], 1);    print_reply = FALSE; @@ -72,8 +73,12 @@ main (int argc, char *argv[])  	usage (argv[0], 0);        else if (arg[0] == '-')  	usage (argv[0], 1); +      else if (path == NULL) +        path = arg; +      else if (name == NULL) +        name = arg;        else -	name = arg; +        usage (argv[0], 1);      }    if (name == NULL) @@ -117,9 +122,10 @@ main (int argc, char *argv[])          }        *last_dot = '\0'; -      message = dbus_message_new_method_call (name, -                                              last_dot + 1, -                                              NULL); +      message = dbus_message_new_method_call (NULL, +                                              path, +                                              name, +                                              last_dot + 1);      }    else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL)      { @@ -134,7 +140,7 @@ main (int argc, char *argv[])          }        *last_dot = '\0'; -      message = dbus_message_new_signal (name, last_dot + 1); +      message = dbus_message_new_signal (path, name, last_dot + 1);      }    else      { | 
