From 95717a938b237d12211935f6a7467ef610288fe5 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 18 Aug 2003 15:27:33 +0000 Subject: 2003-08-17 Havoc Pennington This doesn't compile yet, but syncing up so I can hack on it from work. What are branches for if not broken code? ;-) * dbus/dbus-protocol.h: remove DBUS_HEADER_FIELD_NAME, add DBUS_HEADER_FIELD_INTERFACE, DBUS_HEADER_FIELD_MEMBER, DBUS_HEADER_FIELD_ERROR_NAME * dbus/dbus-hash.c: Introduce DBUS_HASH_TWO_STRINGS as hack to use for the interface+member pairs (string_hash): change to use g_str_hash algorithm (find_direct_function, find_string_function): refactor these to share most code. * dbus/dbus-message.c: port all of this over to support interface/member fields instead of name field * dbus/dbus-object-registry.c: port over * dbus/dbus-string.c (_dbus_string_validate_interface): rename from _dbus_string_validate_name * bus/dbus-daemon-1.1: change file format for the / stuff to match new message naming scheme * bus/policy.c: port over * bus/config-parser.c: parse new format --- dbus/dbus-bus.c | 25 +-- dbus/dbus-connection.c | 54 +++++-- dbus/dbus-hash.c | 378 +++++++++++++++++++++++++++++++++---------- dbus/dbus-hash.h | 115 ++++++------- dbus/dbus-message.c | 386 ++++++++++++++++++++++++++++++++++++-------- dbus/dbus-message.h | 22 ++- dbus/dbus-object-registry.c | 89 ++++++---- dbus/dbus-object-registry.h | 6 +- dbus/dbus-protocol.h | 55 ++++--- dbus/dbus-string.c | 88 +++++++++- dbus/dbus-string.h | 8 +- 11 files changed, 924 insertions(+), 302 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 214978da..445606e2 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -32,6 +32,10 @@ * @ingroup DBus * @brief Functions for communicating with the message bus * + * + * @todo get rid of most of these; they should be done + * with DBusGProxy and the Qt equivalent, i.e. the same + * way any other interface would be used. */ @@ -398,8 +402,9 @@ dbus_bus_register (DBusConnection *connection, return TRUE; } - message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello", + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (!message) @@ -516,9 +521,9 @@ 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_MESSAGE_ACQUIRE_SERVICE, - DBUS_SERVICE_DBUS); - + message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "AcquireService", + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) { @@ -590,8 +595,9 @@ 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_MESSAGE_SERVICE_EXISTS, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceExists", + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) { _DBUS_SET_OOM (error); @@ -652,8 +658,9 @@ dbus_bus_activate_service (DBusConnection *connection, DBusMessage *msg; DBusMessage *reply; - msg = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + msg = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService", + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); 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 bc26a3ec..7be35b4c 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -296,9 +296,11 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection, _dbus_connection_wakeup_mainloop (connection); - _dbus_assert (dbus_message_get_name (message) != NULL); _dbus_verbose ("Message %p (%s) added to incoming queue %p, %d incoming\n", - message, dbus_message_get_name (message), + message, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", connection, connection->n_incoming); } @@ -381,7 +383,10 @@ _dbus_connection_message_sent (DBusConnection *connection, connection->n_outgoing -= 1; _dbus_verbose ("Message %p (%s) removed from outgoing queue %p, %d left to send\n", - message, dbus_message_get_name (message), + message, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", connection, connection->n_outgoing); /* Save this link in the link cache also */ @@ -820,7 +825,9 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (io_path_cond == NULL) goto error; - disconnect_message = dbus_message_new_signal (DBUS_MESSAGE_LOCAL_DISCONNECT); + disconnect_message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnect"); + if (disconnect_message == NULL) goto error; @@ -1482,7 +1489,9 @@ _dbus_connection_send_preallocated_unlocked (DBusConnection *connection, _dbus_verbose ("Message %p (%s) added to outgoing queue %p, %d pending to send\n", message, - dbus_message_get_name (message), + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", connection, connection->n_outgoing); @@ -1530,7 +1539,12 @@ dbus_connection_send_preallocated (DBusConnection *connection, _dbus_return_if_fail (preallocated != NULL); _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (preallocated->connection == connection); - _dbus_return_if_fail (dbus_message_get_name (message) != NULL); + _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL || + (dbus_message_get_interface (message) != NULL && + dbus_message_get_member (message) != NULL)); + _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL || + (dbus_message_get_interface (message) != NULL && + dbus_message_get_member (message) != NULL)); CONNECTION_LOCK (connection); _dbus_connection_send_preallocated_unlocked (connection, @@ -1854,8 +1868,7 @@ _dbus_connection_block_for_reply (DBusConnection *connection, { status = _dbus_connection_get_dispatch_status_unlocked (connection); - _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply %s\n", - dbus_message_get_name (reply)); + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n"); /* Unlocks, and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); @@ -2148,7 +2161,10 @@ _dbus_connection_pop_message_link_unlocked (DBusConnection *connection) connection->n_incoming -= 1; _dbus_verbose ("Message %p (%s) removed from incoming queue %p, %d incoming\n", - link->data, dbus_message_get_name (link->data), + link->data, + dbus_message_get_interface (link->data) ? + dbus_message_get_interface (link->data) : + "no interface", connection, connection->n_incoming); return link; @@ -2194,7 +2210,10 @@ _dbus_connection_putback_message_link_unlocked (DBusConnection *connection, connection->n_incoming += 1; _dbus_verbose ("Message %p (%s) put back into queue %p, %d incoming\n", - message_link->data, dbus_message_get_name (message_link->data), + message_link->data, + dbus_message_get_interface (message_link->data) ? + dbus_message_get_interface (message_link->data) : + "no interface", connection, connection->n_incoming); } @@ -2523,7 +2542,10 @@ dbus_connection_dispatch (DBusConnection *connection) * since we acquired the dispatcher */ _dbus_verbose (" running object handler on message %p (%s)\n", - message, dbus_message_get_name (message)); + message, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface"); result = _dbus_object_registry_handle_and_unlock (connection->objects, message); @@ -2549,8 +2571,9 @@ dbus_connection_dispatch (DBusConnection *connection) } if (!_dbus_string_append_printf (&str, - "Method \"%s\" doesn't exist\n", - dbus_message_get_name (message))) + "Method \"%s\" on interface \"%s\" doesn't exist\n", + dbus_message_get_member (message), + dbus_message_get_interface (message))) { _dbus_string_free (&str); result = DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -2586,7 +2609,10 @@ dbus_connection_dispatch (DBusConnection *connection) } _dbus_verbose (" done dispatching %p (%s) on connection %p\n", message, - dbus_message_get_name (message), connection); + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", + connection); out: if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c index 2c410010..f4547815 100644 --- a/dbus/dbus-hash.c +++ b/dbus/dbus-hash.c @@ -221,26 +221,32 @@ typedef struct int n_entries_on_init; /**< used to detect table resize since initialization */ } DBusRealHashIter; -static DBusHashEntry* find_direct_function (DBusHashTable *table, - void *key, - dbus_bool_t create_if_not_found, - DBusHashEntry ***bucket, - DBusPreallocatedHash *preallocated); -static DBusHashEntry* find_string_function (DBusHashTable *table, - void *key, - dbus_bool_t create_if_not_found, - DBusHashEntry ***bucket, - DBusPreallocatedHash *preallocated); -static unsigned int string_hash (const char *str); -static void rebuild_table (DBusHashTable *table); -static DBusHashEntry* alloc_entry (DBusHashTable *table); -static void remove_entry (DBusHashTable *table, - DBusHashEntry **bucket, - DBusHashEntry *entry); -static void free_entry (DBusHashTable *table, - DBusHashEntry *entry); -static void free_entry_data (DBusHashTable *table, - DBusHashEntry *entry); +static DBusHashEntry* find_direct_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated); +static DBusHashEntry* find_string_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated); +static DBusHashEntry* find_two_strings_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated); +static unsigned int string_hash (const char *str); +static unsigned int two_strings_hash (const char *str); +static void rebuild_table (DBusHashTable *table); +static DBusHashEntry* alloc_entry (DBusHashTable *table); +static void remove_entry (DBusHashTable *table, + DBusHashEntry **bucket, + DBusHashEntry *entry); +static void free_entry (DBusHashTable *table, + DBusHashEntry *entry); +static void free_entry_data (DBusHashTable *table, + DBusHashEntry *entry); /** @} */ @@ -323,6 +329,9 @@ _dbus_hash_table_new (DBusHashType type, case DBUS_HASH_STRING: table->find_function = find_string_function; break; + case DBUS_HASH_TWO_STRINGS: + table->find_function = find_two_strings_function; + break; default: _dbus_assert_not_reached ("Unknown hash table type"); break; @@ -684,6 +693,24 @@ _dbus_hash_iter_get_string_key (DBusHashIter *iter) return real->entry->key; } +/** + * Gets the key for the current entry. + * Only works for hash tables of type #DBUS_HASH_TWO_STRINGS + * @param iter the hash table iterator. + */ +const char* +_dbus_hash_iter_get_two_strings_key (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + return real->entry->key; +} + /** * A low-level but efficient interface for manipulating the hash * table. It's efficient because you can get, set, and optionally @@ -803,64 +830,63 @@ add_entry (DBusHashTable *table, return entry; } +/* This is g_str_hash from GLib which was + * extensively discussed/tested/profiled + */ static unsigned int string_hash (const char *str) { - register unsigned int result; - register int c; + const char *p = str; + unsigned int h = *p; - /* - * I tried a zillion different hash functions and asked many other - * people for advice. Many people had their own favorite functions, - * all different, but no-one had much idea why they were good ones. - * I chose the one below (multiply by 9 and add new character) - * because of the following reasons: - * - * 1. Multiplying by 10 is perfect for keys that are decimal strings, - * and multiplying by 9 is just about as good. - * 2. Times-9 is (shift-left-3) plus (old). This means that each - * character's bits hang around in the low-order bits of the - * hash value for ever, plus they spread fairly rapidly up to - * the high-order bits to fill out the hash value. This seems - * works well both for decimal and non-decimal strings. - */ + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; - /* FIXME the hash function in GLib is better than this one */ - - result = 0; - while (TRUE) - { - c = *str; - str++; - if (c == 0) - break; - - result += (result << 3) + c; - } + return h; +} + +/* This hashes a memory block with two nul-terminated strings + * in it, used in dbus-object-registry.c at the moment. + */ +static unsigned int +two_strings_hash (const char *str) +{ + const char *p = str; + unsigned int h = *p; + + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; - return result; + return h; } +typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b); + static DBusHashEntry* -find_string_function (DBusHashTable *table, - void *key, - dbus_bool_t create_if_not_found, - DBusHashEntry ***bucket, - DBusPreallocatedHash *preallocated) +find_generic_function (DBusHashTable *table, + void *key, + unsigned int idx, + KeyCompareFunc compare_func, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) { DBusHashEntry *entry; - unsigned int idx; if (bucket) *bucket = NULL; - - idx = string_hash (key) & table->mask; /* Search all of the entries in this bucket. */ entry = table->buckets[idx]; while (entry != NULL) { - if (strcmp (key, entry->key) == 0) + if ((compare_func == NULL && key == entry->key) || + (compare_func != NULL && (* compare_func) (key, entry->key) == 0)) { if (bucket) *bucket = &(table->buckets[idx]); @@ -878,50 +904,75 @@ find_string_function (DBusHashTable *table, entry = add_entry (table, idx, key, bucket, preallocated); else if (preallocated) _dbus_hash_table_free_preallocated_entry (table, preallocated); - + return entry; } static DBusHashEntry* -find_direct_function (DBusHashTable *table, +find_string_function (DBusHashTable *table, void *key, dbus_bool_t create_if_not_found, DBusHashEntry ***bucket, DBusPreallocatedHash *preallocated) { - DBusHashEntry *entry; unsigned int idx; + + idx = string_hash (key) & table->mask; - if (bucket) - *bucket = NULL; + return find_generic_function (table, key, idx, + (KeyCompareFunc) strcmp, create_if_not_found, bucket, + preallocated); +} + +static int +two_strings_cmp (const char *a, + const char *b) +{ + size_t len_a; + size_t len_b; + int res; - idx = RANDOM_INDEX (table, key) & table->mask; + res = strcmp (a, b); + if (res != 0) + return res; - /* Search all of the entries in this bucket. */ - entry = table->buckets[idx]; - while (entry != NULL) - { - if (key == entry->key) - { - if (bucket) - *bucket = &(table->buckets[idx]); + len_a = strlen (a); + len_b = strlen (b); - if (preallocated) - _dbus_hash_table_free_preallocated_entry (table, preallocated); - - return entry; - } - - entry = entry->next; - } + return strcmp (a + len_a + 1, b + len_b + 1); +} - /* Entry not found. Add a new one to the bucket. */ - if (create_if_not_found) - entry = add_entry (table, idx, key, bucket, preallocated); - else if (preallocated) - _dbus_hash_table_free_preallocated_entry (table, preallocated); +static DBusHashEntry* +find_two_strings_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) +{ + unsigned int idx; + + idx = two_strings_hash (key) & table->mask; - return entry; + return find_generic_function (table, key, idx, + (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket, + preallocated); +} + +static DBusHashEntry* +find_direct_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) +{ + unsigned int idx; + + idx = RANDOM_INDEX (table, key) & table->mask; + + + return find_generic_function (table, key, idx, + NULL, create_if_not_found, bucket, + preallocated); } static void @@ -1021,6 +1072,9 @@ rebuild_table (DBusHashTable *table) case DBUS_HASH_STRING: idx = string_hash (entry->key) & table->mask; break; + case DBUS_HASH_TWO_STRINGS: + idx = two_strings_hash (entry->key) & table->mask; + break; case DBUS_HASH_INT: case DBUS_HASH_ULONG: case DBUS_HASH_POINTER: @@ -1069,6 +1123,31 @@ _dbus_hash_table_lookup_string (DBusHashTable *table, return NULL; } +/** + * Looks up the value for a given string in a hash table + * of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value + * is not present. (A not-present entry is indistinguishable + * from an entry with a value of %NULL.) + * @param table the hash table. + * @param key the string to look up. + * @returns the value of the hash entry. + */ +void* +_dbus_hash_table_lookup_two_strings (DBusHashTable *table, + const char *key) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS); + + entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL); + + if (entry) + return entry->value; + else + return NULL; +} + /** * Looks up the value for a given integer in a hash table * of type #DBUS_HASH_INT. Returns %NULL if the value @@ -1175,6 +1254,34 @@ _dbus_hash_table_remove_string (DBusHashTable *table, return FALSE; } +/** + * Removes the hash entry for the given key. If no hash entry + * for the key exists, does nothing. + * + * @param table the hash table. + * @param key the hash key. + * @returns #TRUE if the entry existed + */ +dbus_bool_t +_dbus_hash_table_remove_two_strings (DBusHashTable *table, + const char *key) +{ + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS); + + entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL); + + if (entry) + { + remove_entry (table, bucket, entry); + return TRUE; + } + else + return FALSE; +} + /** * Removes the hash entry for the given key. If no hash entry * for the key exists, does nothing. @@ -1296,6 +1403,40 @@ _dbus_hash_table_insert_string (DBusHashTable *table, return TRUE; } +/** + * Creates a hash entry with the given key and value. + * The key and value are not copied; they are stored + * in the hash table by reference. If an entry with the + * given key already exists, the previous key and value + * are overwritten (and freed if the hash table has + * a key_free_function and/or value_free_function). + * + * Returns #FALSE if memory for the new hash entry + * can't be allocated. + * + * @param table the hash table. + * @param key the hash entry key. + * @param value the hash entry value. + */ +dbus_bool_t +_dbus_hash_table_insert_two_strings (DBusHashTable *table, + char *key, + void *value) +{ + DBusPreallocatedHash *preallocated; + + _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS); + + preallocated = _dbus_hash_table_preallocate_entry (table); + if (preallocated == NULL) + return FALSE; + + _dbus_hash_table_insert_string_preallocated (table, preallocated, + key, value); + + return TRUE; +} + /** * Creates a hash entry with the given key and value. * The key and value are not copied; they are stored @@ -1536,6 +1677,28 @@ count_entries (DBusHashTable *table) return count; } +/* Copy the foo\0bar\0 double string thing */ +static char* +_dbus_strdup2 (const char *str) +{ + size_t len; + char *copy; + + if (str == NULL) + return NULL; + + len = strlen (str); + len += strlen ((str + len + 1)); + + copy = dbus_malloc (len + 2); + if (copy == NULL) + return NULL; + + memcpy (copy, str, len + 2); + + return copy; +} + /** * @ingroup DBusHashTableInternals * Unit test for DBusHashTable @@ -1548,6 +1711,7 @@ _dbus_hash_test (void) DBusHashTable *table1; DBusHashTable *table2; DBusHashTable *table3; + DBusHashTable *table4; DBusHashIter iter; #define N_HASH_KEYS 5000 char **keys; @@ -1569,7 +1733,16 @@ _dbus_hash_test (void) i = 0; while (i < N_HASH_KEYS) { - sprintf (keys[i], "Hash key %d", i); + int len; + + /* all the hash keys are TWO_STRINGS, but + * then we can also use those as regular strings. + */ + + len = sprintf (keys[i], "Hash key %d", i); + sprintf (keys[i] + len + 1, "Two string %d", i); + _dbus_assert (*(keys[i] + len) == '\0'); + _dbus_assert (*(keys[i] + len + 1) != '\0'); ++i; } printf ("... done.\n"); @@ -1588,6 +1761,12 @@ _dbus_hash_test (void) NULL, dbus_free); if (table3 == NULL) goto out; + + table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS, + dbus_free, dbus_free); + if (table4 == NULL) + goto out; + /* Insert and remove a bunch of stuff, counting the table in between * to be sure it's not broken and that iteration works @@ -1624,10 +1803,22 @@ _dbus_hash_test (void) if (!_dbus_hash_table_insert_ulong (table3, i, value)) goto out; + + key = _dbus_strdup2 (keys[i]); + if (key == NULL) + goto out; + value = _dbus_strdup ("Value!"); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_string (table4, + key, value)) + goto out; _dbus_assert (count_entries (table1) == i + 1); _dbus_assert (count_entries (table2) == i + 1); _dbus_assert (count_entries (table3) == i + 1); + _dbus_assert (count_entries (table4) == i + 1); value = _dbus_hash_table_lookup_string (table1, keys[i]); _dbus_assert (value != NULL); @@ -1640,6 +1831,10 @@ _dbus_hash_test (void) value = _dbus_hash_table_lookup_ulong (table3, i); _dbus_assert (value != NULL); _dbus_assert (strcmp (value, keys[i]) == 0); + + value = _dbus_hash_table_lookup_ulong (table4, i); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, keys[i]) == 0); ++i; } @@ -1654,9 +1849,13 @@ _dbus_hash_test (void) _dbus_hash_table_remove_ulong (table3, i); + _dbus_hash_table_remove_two_strings (table4, + keys[i]); + _dbus_assert (count_entries (table1) == i); _dbus_assert (count_entries (table2) == i); _dbus_assert (count_entries (table3) == i); + _dbus_assert (count_entries (table4) == i); --i; } @@ -1664,12 +1863,15 @@ _dbus_hash_test (void) _dbus_hash_table_ref (table1); _dbus_hash_table_ref (table2); _dbus_hash_table_ref (table3); + _dbus_hash_table_ref (table4); _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); _dbus_hash_table_unref (table3); + _dbus_hash_table_unref (table4); _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); _dbus_hash_table_unref (table3); + _dbus_hash_table_unref (table4); table3 = NULL; /* Insert a bunch of stuff then check diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h index 566d4021..25b81dd6 100644 --- a/dbus/dbus-hash.h +++ b/dbus/dbus-hash.h @@ -52,61 +52,68 @@ typedef struct DBusHashIter DBusHashIter; */ typedef enum { - DBUS_HASH_STRING, /**< Hash keys are strings. */ - DBUS_HASH_INT, /**< Hash keys are integers. */ - DBUS_HASH_POINTER, /**< Hash keys are pointers. */ - DBUS_HASH_ULONG /**< Hash keys are unsigned long. */ + DBUS_HASH_STRING, /**< Hash keys are strings. */ + DBUS_HASH_TWO_STRINGS, /**< Hash key is two strings in one memory block, i.e. foo\0bar\0 */ + DBUS_HASH_INT, /**< Hash keys are integers. */ + DBUS_HASH_POINTER, /**< Hash keys are pointers. */ + DBUS_HASH_ULONG /**< Hash keys are unsigned long. */ } DBusHashType; - -DBusHashTable* _dbus_hash_table_new (DBusHashType type, - DBusFreeFunction key_free_function, - DBusFreeFunction value_free_function); -void _dbus_hash_table_ref (DBusHashTable *table); -void _dbus_hash_table_unref (DBusHashTable *table); -void _dbus_hash_iter_init (DBusHashTable *table, - DBusHashIter *iter); -dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter); -void _dbus_hash_iter_remove_entry (DBusHashIter *iter); -void* _dbus_hash_iter_get_value (DBusHashIter *iter); -void _dbus_hash_iter_set_value (DBusHashIter *iter, - void *value); -int _dbus_hash_iter_get_int_key (DBusHashIter *iter); -const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter); -unsigned long _dbus_hash_iter_get_ulong_key (DBusHashIter *iter); -dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table, - void *key, - dbus_bool_t create_if_not_found, - DBusHashIter *iter); -void* _dbus_hash_table_lookup_string (DBusHashTable *table, - const char *key); -void* _dbus_hash_table_lookup_int (DBusHashTable *table, - int key); -void* _dbus_hash_table_lookup_pointer (DBusHashTable *table, - void *key); -void* _dbus_hash_table_lookup_ulong (DBusHashTable *table, - unsigned long key); -dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table, - const char *key); -dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table, - int key); -dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table, - void *key); -dbus_bool_t _dbus_hash_table_remove_ulong (DBusHashTable *table, - unsigned long key); -dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table, - char *key, - void *value); -dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table, - int key, - void *value); -dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table, - void *key, - void *value); -dbus_bool_t _dbus_hash_table_insert_ulong (DBusHashTable *table, - unsigned long key, - void *value); -int _dbus_hash_table_get_n_entries (DBusHashTable *table); - +DBusHashTable* _dbus_hash_table_new (DBusHashType type, + DBusFreeFunction key_free_function, + DBusFreeFunction value_free_function); +void _dbus_hash_table_ref (DBusHashTable *table); +void _dbus_hash_table_unref (DBusHashTable *table); +void _dbus_hash_iter_init (DBusHashTable *table, + DBusHashIter *iter); +dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter); +void _dbus_hash_iter_remove_entry (DBusHashIter *iter); +void* _dbus_hash_iter_get_value (DBusHashIter *iter); +void _dbus_hash_iter_set_value (DBusHashIter *iter, + void *value); +int _dbus_hash_iter_get_int_key (DBusHashIter *iter); +const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter); +const char* _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter); +unsigned long _dbus_hash_iter_get_ulong_key (DBusHashIter *iter); +dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashIter *iter); +void* _dbus_hash_table_lookup_string (DBusHashTable *table, + const char *key); +void* _dbus_hash_table_lookup_two_strings (DBusHashTable *table, + const char *key); +void* _dbus_hash_table_lookup_int (DBusHashTable *table, + int key); +void* _dbus_hash_table_lookup_pointer (DBusHashTable *table, + void *key); +void* _dbus_hash_table_lookup_ulong (DBusHashTable *table, + unsigned long key); +dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table, + const char *key); +dbus_bool_t _dbus_hash_table_remove_two_strings (DBusHashTable *table, + const char *key); +dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table, + int key); +dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table, + void *key); +dbus_bool_t _dbus_hash_table_remove_ulong (DBusHashTable *table, + unsigned long key); +dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table, + char *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_two_strings (DBusHashTable *table, + char *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table, + int key, + void *value); +dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table, + void *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_ulong (DBusHashTable *table, + unsigned long key, + void *value); +int _dbus_hash_table_get_n_entries (DBusHashTable *table); /* Preallocation */ typedef struct DBusPreallocatedHash DBusPreallocatedHash; diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 5f3d01e0..e5bbcab1 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -47,7 +47,9 @@ enum FIELD_HEADER_LENGTH, FIELD_BODY_LENGTH, FIELD_CLIENT_SERIAL, - FIELD_NAME, + FIELD_INTERFACE, + FIELD_MEMBER, + FIELD_ERROR_NAME, FIELD_SERVICE, FIELD_SENDER, FIELD_REPLY_SERIAL, @@ -60,7 +62,9 @@ static dbus_bool_t field_is_named[FIELD_LAST] = FALSE, /* FIELD_HEADER_LENGTH */ FALSE, /* FIELD_BODY_LENGTH */ FALSE, /* FIELD_CLIENT_SERIAL */ - TRUE, /* FIELD_NAME */ + TRUE, /* FIELD_INTERFACE */ + TRUE, /* FIELD_MEMBER */ + TRUE, /* FIELD_ERROR_NAME */ TRUE, /* FIELD_SERVICE */ TRUE, /* FIELD_SENDER */ TRUE /* FIELD_REPLY_SERIAL */ @@ -593,9 +597,17 @@ set_string_field (DBusMessage *message, return append_string_field (message, field, DBUS_HEADER_FIELD_SENDER, value); - case FIELD_NAME: + case FIELD_INTERFACE: return append_string_field (message, field, - DBUS_HEADER_FIELD_NAME, + DBUS_HEADER_FIELD_INTERFACE, + value); + case FIELD_MEMBER: + return append_string_field (message, field, + DBUS_HEADER_FIELD_MEMBER, + value); + case FIELD_ERROR_NAME: + return append_string_field (message, field, + DBUS_HEADER_FIELD_ERROR_NAME, value); case FIELD_SERVICE: return append_string_field (message, field, @@ -817,10 +829,16 @@ _dbus_message_remove_size_counter (DBusMessage *message, static dbus_bool_t dbus_message_create_header (DBusMessage *message, int type, - const char *name, + const char *interface, + const char *member, + const char *error_name, const char *service) { unsigned int flags; + + _dbus_assert ((interface && member) || + (error_name) || + !(interface || member || error_name)); if (!_dbus_string_append_byte (&message->header, message->byte_order)) return FALSE; @@ -857,12 +875,30 @@ dbus_message_create_header (DBusMessage *message, return FALSE; } - if (name != NULL) + if (interface != NULL) + { + if (!append_string_field (message, + FIELD_INTERFACE, + DBUS_HEADER_FIELD_INTERFACE, + interface)) + return FALSE; + } + + if (member != NULL) { if (!append_string_field (message, - FIELD_NAME, - DBUS_HEADER_FIELD_NAME, - name)) + FIELD_MEMBER, + DBUS_HEADER_FIELD_MEMBER, + member)) + return FALSE; + } + + if (error_name != NULL) + { + if (!append_string_field (message, + FIELD_ERROR_NAME, + DBUS_HEADER_FIELD_ERROR_NAME, + error_name)) return FALSE; } @@ -979,7 +1015,7 @@ dbus_message_new (int message_type) if (!dbus_message_create_header (message, message_type, - NULL, NULL)) + NULL, NULL, NULL, NULL)) { dbus_message_unref (message); return NULL; @@ -995,18 +1031,21 @@ dbus_message_new (int message_type) * this is appropriate when using D-BUS in a peer-to-peer context (no * message bus). * - * @param name name of the message + * @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 *name, +dbus_message_new_method_call (const char *interface, + const char *method, const char *destination_service) { DBusMessage *message; - _dbus_return_val_if_fail (name != NULL, NULL); + _dbus_return_val_if_fail (interface != NULL, NULL); + _dbus_return_val_if_fail (method != NULL, NULL); message = dbus_message_new_empty_header (); if (message == NULL) @@ -1014,7 +1053,7 @@ dbus_message_new_method_call (const char *name, if (!dbus_message_create_header (message, DBUS_MESSAGE_TYPE_METHOD_CALL, - name, destination_service)) + interface, method, NULL, destination_service)) { dbus_message_unref (message); return NULL; @@ -1036,14 +1075,12 @@ DBusMessage* dbus_message_new_method_return (DBusMessage *method_call) { DBusMessage *message; - const char *sender, *name; + const char *sender; _dbus_return_val_if_fail (method_call != NULL, NULL); sender = get_string_field (method_call, FIELD_SENDER, NULL); - name = get_string_field (method_call, - FIELD_NAME, NULL); /* sender is allowed to be null here in peer-to-peer case */ @@ -1053,7 +1090,7 @@ dbus_message_new_method_return (DBusMessage *method_call) if (!dbus_message_create_header (message, DBUS_MESSAGE_TYPE_METHOD_RETURN, - name, sender)) + NULL, NULL, NULL, sender)) { dbus_message_unref (message); return NULL; @@ -1071,15 +1108,18 @@ dbus_message_new_method_return (DBusMessage *method_call) /** * Constructs a new message representing a signal emission. Returns - * #NULL if memory can't be allocated for the message. The name - * passed in is the name of the signal. + * #NULL if memory can't be allocated for the message. + * A signal is identified by its originating interface, and + * the name of the signal. * + * @param interface the interface the signal is emitted from * @param name name of the signal * @returns a new DBusMessage, free with dbus_message_unref() * @see dbus_message_unref() */ DBusMessage* -dbus_message_new_signal (const char *name) +dbus_message_new_signal (const char *interface, + const char *name) { DBusMessage *message; @@ -1091,7 +1131,7 @@ dbus_message_new_signal (const char *name) if (!dbus_message_create_header (message, DBUS_MESSAGE_TYPE_SIGNAL, - name, NULL)) + interface, name, NULL, NULL)) { dbus_message_unref (message); return NULL; @@ -1134,7 +1174,7 @@ dbus_message_new_error (DBusMessage *reply_to, if (!dbus_message_create_header (message, DBUS_MESSAGE_TYPE_ERROR, - error_name, sender)) + NULL, NULL, error_name, sender)) { dbus_message_unref (message); return NULL; @@ -1312,46 +1352,139 @@ dbus_message_get_type (DBusMessage *message) return type; } +/** + * Sets the interface this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or + * the interface a signal is being emitted from + * (for DBUS_MESSAGE_TYPE_SIGNAL). + * + * @param message the message + * @param interface the interface + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_interface (DBusMessage *message, + const char *interface) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + + if (interface == NULL) + { + delete_string_field (message, FIELD_INTERFACE); + return TRUE; + } + else + { + return set_string_field (message, + FIELD_INTERFACE, + interface); + } +} /** - * Sets the message name. + * Gets the interface this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted + * from (for DBUS_MESSAGE_TYPE_SIGNAL). + * The interface name is fully-qualified (namespaced). * * @param message the message - * @param name the name + * @returns the message interface (should not be freed) + */ +const char* +dbus_message_get_interface (DBusMessage *message) +{ + _dbus_return_val_if_fail (message != NULL, NULL); + + return get_string_field (message, FIELD_INTERFACE, NULL); +} + +/** + * Sets the interface member being invoked + * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted + * (DBUS_MESSAGE_TYPE_SIGNAL). + * The interface name is fully-qualified (namespaced). + * + * @param message the message + * @param member the member * @returns #FALSE if not enough memory */ dbus_bool_t -dbus_message_set_name (DBusMessage *message, - const char *name) +dbus_message_set_member (DBusMessage *message, + const char *member) { _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (!message->locked, FALSE); - if (name == NULL) + if (member == NULL) { - delete_string_field (message, FIELD_NAME); + delete_string_field (message, FIELD_MEMBER); return TRUE; } else { return set_string_field (message, - FIELD_NAME, - name); + FIELD_MEMBER, + member); } } /** - * Gets the name of a message. + * Gets the interface member being invoked + * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted + * (DBUS_MESSAGE_TYPE_SIGNAL). + * + * @param message the message + * @returns the member name (should not be freed) + */ +const char* +dbus_message_get_member (DBusMessage *message) +{ + _dbus_return_val_if_fail (message != NULL, NULL); + + return get_string_field (message, FIELD_MEMBER, NULL); +} + +/** + * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR). + * The name is fully-qualified (namespaced). * * @param message the message - * @returns the message name (should not be freed) + * @param name the name + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_error_name (DBusMessage *message, + const char *error_name) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + + if (error_name == NULL) + { + delete_string_field (message, FIELD_ERROR_NAME); + return TRUE; + } + else + { + return set_string_field (message, + FIELD_ERROR_NAME, + error_name); + } +} + +/** + * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only). + * + * @param message the message + * @returns the error name (should not be freed) */ const char* -dbus_message_get_name (DBusMessage *message) +dbus_message_get_error_name (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, NULL); - return get_string_field (message, FIELD_NAME, NULL); + return get_string_field (message, FIELD_ERROR_NAME, NULL); } /** @@ -3917,27 +4050,54 @@ dbus_message_get_sender (DBusMessage *message) } /** - * Checks whether the message has the given name. - * If the message has no name or has a different - * name, returns #FALSE. + * Checks whether the message has the given interface field. If the + * message has no interface field or has a different one, returns + * #FALSE. + * + * @param message the message + * @param interface the name to check (must not be #NULL) + * + * @returns #TRUE if the message has the given name + */ +dbus_bool_t +dbus_message_has_interface (DBusMessage *message, + const char *interface) +{ + const char *n; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (interface != NULL, FALSE); + + n = dbus_message_get_interface (message); + + if (n && strcmp (n, interface) == 0) + return TRUE; + else + return FALSE; +} + + +/** + * Checks whether the message has the given member field. If the + * message has no member field or has a different one, returns #FALSE. * * @param message the message - * @param name the name to check (must not be #NULL) + * @param member the name to check (must not be #NULL) * * @returns #TRUE if the message has the given name */ dbus_bool_t -dbus_message_has_name (DBusMessage *message, - const char *name) +dbus_message_has_member (DBusMessage *message, + const char *member) { const char *n; _dbus_return_val_if_fail (message != NULL, FALSE); - _dbus_return_val_if_fail (name != NULL, FALSE); + _dbus_return_val_if_fail (member != NULL, FALSE); - n = dbus_message_get_name (message); + n = dbus_message_get_member (message); - if (n && strcmp (n, name) == 0) + if (n && strcmp (n, member) == 0) return TRUE; else return FALSE; @@ -4034,7 +4194,7 @@ dbus_set_error_from_message (DBusError *error, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID); - dbus_set_error (error, dbus_message_get_name (message), + dbus_set_error (error, dbus_message_get_error_name (message), str ? "%s" : NULL, str); dbus_free (str); @@ -4216,9 +4376,17 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader, (((dbus_uint32_t)c) << 8) | \ ((dbus_uint32_t)d)) -/** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */ -#define DBUS_HEADER_FIELD_NAME_AS_UINT32 \ - FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e') +/** 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') + +/** DBUS_HEADER_FIELD_MEMBER packed into a dbus_uint32_t */ +#define DBUS_HEADER_FIELD_MEMBER_AS_UINT32 \ + FOUR_CHARS_TO_UINT32 ('m', 'e', 'b', 'r') + +/** DBUS_HEADER_FIELD_ERROR_NAME packed into a dbus_uint32_t */ +#define DBUS_HEADER_FIELD_ERROR_NAME_AS_UINT32 \ + FOUR_CHARS_TO_UINT32 ('e', 'r', 'n', 'm') /** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */ #define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \ @@ -4267,23 +4435,41 @@ decode_string_field (const DBusString *data, _dbus_string_init_const (&tmp, _dbus_string_get_const_data (data) + string_data_pos); - if (field == FIELD_NAME) + if (field == FIELD_INTERFACE) { - if (!_dbus_string_validate_name (&tmp, 0, _dbus_string_get_length (&tmp))) + if (!_dbus_string_validate_interface (&tmp, 0, _dbus_string_get_length (&tmp))) { _dbus_verbose ("%s field has invalid content \"%s\"\n", field_name, _dbus_string_get_const_data (&tmp)); return FALSE; } - if (_dbus_string_starts_with_c_str (&tmp, - DBUS_NAMESPACE_LOCAL_MESSAGE)) + if (_dbus_string_equal_c_str (&tmp, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL)) { - _dbus_verbose ("Message is in the local namespace\n"); + _dbus_verbose ("Message is on the local interface\n"); return FALSE; } } - else + else if (field == FIELD_MEMBER) + { + if (!_dbus_string_validate_member (&tmp, 0, _dbus_string_get_length (&tmp))) + { + _dbus_verbose ("%s field has invalid content \"%s\"\n", + field_name, _dbus_string_get_const_data (&tmp)); + return FALSE; + } + } + else if (field == FIELD_ERROR_NAME) + { + if (!_dbus_string_validate_error_name (&tmp, 0, _dbus_string_get_length (&tmp))) + { + _dbus_verbose ("%s field has invalid content \"%s\"\n", + field_name, _dbus_string_get_const_data (&tmp)); + return FALSE; + } + } + else if (field == FIELD_SERVICE) { if (!_dbus_string_validate_service (&tmp, 0, _dbus_string_get_length (&tmp))) { @@ -4292,6 +4478,10 @@ decode_string_field (const DBusString *data, return FALSE; } } + else + { + _dbus_assert_not_reached ("Unknown field\n"); + } fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4); @@ -4307,6 +4497,7 @@ static dbus_bool_t decode_header_data (const DBusString *data, int header_len, int byte_order, + int message_type, HeaderField fields[FIELD_LAST], int *message_padding) { @@ -4375,13 +4566,27 @@ decode_header_data (const DBusString *data, return FALSE; break; - case DBUS_HEADER_FIELD_NAME_AS_UINT32: + case DBUS_HEADER_FIELD_INTERFACE_AS_UINT32: + if (!decode_string_field (data, fields, pos, type, + FIELD_INTERFACE, + DBUS_HEADER_FIELD_INTERFACE)) + return FALSE; + break; + + case DBUS_HEADER_FIELD_MEMBER_AS_UINT32: if (!decode_string_field (data, fields, pos, type, - FIELD_NAME, - DBUS_HEADER_FIELD_NAME)) + FIELD_MEMBER, + DBUS_HEADER_FIELD_MEMBER)) return FALSE; break; + case DBUS_HEADER_FIELD_ERROR_NAME_AS_UINT32: + if (!decode_string_field (data, fields, pos, type, + FIELD_ERROR_NAME, + DBUS_HEADER_FIELD_ERROR_NAME)) + return FALSE; + break; + case DBUS_HEADER_FIELD_SENDER_AS_UINT32: if (!decode_string_field (data, fields, pos, type, FIELD_SENDER, @@ -4430,12 +4635,37 @@ decode_header_data (const DBusString *data, } } - /* Name field is mandatory */ - if (fields[FIELD_NAME].offset < 0) + /* Depending on message type, enforce presence of certain fields. */ + switch (message_type) { - _dbus_verbose ("No %s field provided\n", - DBUS_HEADER_FIELD_NAME); - return FALSE; + case DBUS_MESSAGE_TYPE_SIGNAL: + case DBUS_MESSAGE_TYPE_METHOD_CALL: + if (fields[FIELD_INTERFACE].offset < 0) + { + _dbus_verbose ("No %s field provided\n", + DBUS_HEADER_FIELD_INTERFACE); + return FALSE; + } + if (fields[FIELD_MEMBER].offset < 0) + { + _dbus_verbose ("No %s field provided\n", + DBUS_HEADER_FIELD_MEMBER); + return FALSE; + } + break; + case DBUS_MESSAGE_TYPE_ERROR: + if (fields[FIELD_ERROR_NAME].offset < 0) + { + _dbus_verbose ("No %s field provided\n", + DBUS_HEADER_FIELD_ERROR_NAME); + return FALSE; + } + break; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + break; + default: + /* An unknown type, spec requires us to ignore it */ + break; } if (message_padding) @@ -4579,7 +4809,8 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) #if 0 _dbus_verbose_bytes_of_string (&loader->data, 0, header_len + body_len); #endif - if (!decode_header_data (&loader->data, header_len, byte_order, + if (!decode_header_data (&loader->data, message_type, + header_len, byte_order, fields, &header_padding)) { _dbus_verbose ("Header was invalid\n"); @@ -6010,15 +6241,19 @@ _dbus_message_test (const char *test_data_dir) _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); - message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); - _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test")); + message = dbus_message_new_method_call ("Foo.TestInterface", + "TestMethod", + "org.freedesktop.DBus.TestService"); + _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); + _dbus_assert (dbus_message_has_interface (message, "Foo.TestInterface")); + _dbus_assert (dbus_message_has_member (message, "TestMethod")); _dbus_message_set_serial (message, 1234); dbus_message_set_sender (message, "org.foo.bar"); _dbus_assert (dbus_message_has_sender (message, "org.foo.bar")); dbus_message_set_sender (message, NULL); _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar")); _dbus_assert (dbus_message_get_serial (message) == 1234); - _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test")); + _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); _dbus_assert (dbus_message_get_no_reply (message) == FALSE); dbus_message_set_no_reply (message, TRUE); @@ -6029,7 +6264,9 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (message); /* Test the vararg functions */ - message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); + message = dbus_message_new_method_call ("Foo.TestInterface", + "TestMethod", + "org.freedesktop.DBus.TestService"); _dbus_message_set_serial (message, 1); dbus_message_append_args (message, DBUS_TYPE_INT32, -0x12345678, @@ -6087,15 +6324,22 @@ _dbus_message_test (const char *test_data_dir) verify_test_message (copy); - name1 = dbus_message_get_name (message); - name2 = dbus_message_get_name (copy); + name1 = dbus_message_get_interface (message); + name2 = dbus_message_get_interface (copy); + + _dbus_assert (strcmp (name1, name2) == 0); + + name1 = dbus_message_get_member (message); + name2 = dbus_message_get_member (copy); _dbus_assert (strcmp (name1, name2) == 0); dbus_message_unref (message); dbus_message_unref (copy); - - message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); + + message = dbus_message_new_method_call ("Foo.TestInterface", + "TestMethod", + "org.freedesktop.DBus.TestService"); _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 1b61c8d1..dc204585 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -58,10 +58,12 @@ struct DBusMessageIter }; DBusMessage* dbus_message_new (int message_type); -DBusMessage* dbus_message_new_method_call (const char *name, +DBusMessage* dbus_message_new_method_call (const char *interface, + const char *method, const char *destination_service); DBusMessage* dbus_message_new_method_return (DBusMessage *method_call); -DBusMessage* dbus_message_new_signal (const char *name); +DBusMessage* dbus_message_new_signal (const char *interface, + const char *name); DBusMessage* dbus_message_new_error (DBusMessage *reply_to, const char *error_name, const char *error_message); @@ -71,9 +73,15 @@ 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_name (DBusMessage *message, +dbus_bool_t dbus_message_set_interface (DBusMessage *message, + const char *interface); +const char* dbus_message_get_interface (DBusMessage *message); +dbus_bool_t dbus_message_set_member (DBusMessage *message, + const char *member); +const char* dbus_message_get_member (DBusMessage *message); +dbus_bool_t dbus_message_set_error_name (DBusMessage *message, const char *name); -const char* dbus_message_get_name (DBusMessage *message); +const char* dbus_message_get_error_name (DBusMessage *message); dbus_bool_t dbus_message_set_destination (DBusMessage *message, const char *destination); const char* dbus_message_get_destination (DBusMessage *message); @@ -83,7 +91,11 @@ const char* dbus_message_get_sender (DBusMessage *message); void dbus_message_set_no_reply (DBusMessage *message, dbus_bool_t no_reply); dbus_bool_t dbus_message_get_no_reply (DBusMessage *message); -dbus_bool_t dbus_message_has_name (DBusMessage *message, +dbus_bool_t dbus_message_has_interface (DBusMessage *message, + const char *interface); +dbus_bool_t dbus_message_has_member (DBusMessage *message, + const char *member); +dbus_bool_t dbus_message_has_error_name (DBusMessage *message, const char *name); dbus_bool_t dbus_message_has_destination (DBusMessage *message, const char *service); diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index d3d175d8..e5a81315 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -63,7 +63,7 @@ struct DBusSignalEntry dbus_uint16_t *connections; /**< Index of each object connected (can have dups for multiple * connections) */ - char name[4]; /**< Name of signal (actually allocated larger) */ + char name[4]; /**< Interface of signal, nul, then name of signal (actually allocated larger) */ }; /* 14 bits for object index, 32K objects */ @@ -144,8 +144,8 @@ _dbus_object_registry_new (DBusConnection *connection) if (interface_table == NULL) goto oom; - signal_table = _dbus_hash_table_new (DBUS_HASH_STRING, - NULL, free_signal_entry); + signal_table = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS, + NULL, free_signal_entry); if (signal_table == NULL) goto oom; @@ -431,32 +431,45 @@ object_remove_from_interfaces (DBusObjectRegistry *registry, static DBusSignalEntry* lookup_signal (DBusObjectRegistry *registry, - const char *name, + const char *signal_interface, + const char *signal_name, dbus_bool_t create_if_not_found) { DBusSignalEntry *entry; int sz; - int len; + size_t len_interface, len_name; + char buf[2 * DBUS_MAXIMUM_NAME_LENGTH + 2]; + + /* This is all a little scary and maybe we shouldn't jump + * through these hoops just to save some bytes. + */ - entry = _dbus_hash_table_lookup_string (registry->signal_table, - name); + len_interface = strlen (signal_interface); + len_name = strlen (signal_name); + + _dbus_assert (len_interface + len_name + 2 <= sizeof (buf)); + + memcpy (buf, signal_interface, len_interface + 1); + memcpy (buf + len_interface + 1, signal_name, len_name + 1); + + entry = _dbus_hash_table_lookup_two_strings (registry->signal_table, + buf); if (entry != NULL || !create_if_not_found) return entry; _dbus_assert (create_if_not_found); - len = strlen (name); - sz = _DBUS_STRUCT_OFFSET (DBusSignalEntry, name) + len + 1; + sz = _DBUS_STRUCT_OFFSET (DBusSignalEntry, name) + len_interface + len_name + 2; entry = dbus_malloc (sz); if (entry == NULL) return NULL; entry->n_connections = 0; entry->n_allocated = 0; entry->connections = NULL; - memcpy (entry->name, name, len + 1); + memcpy (entry->name, buf, len_interface + len_name + 2); - if (!_dbus_hash_table_insert_string (registry->signal_table, - entry->name, entry)) + if (!_dbus_hash_table_insert_two_strings (registry->signal_table, + entry->name, entry)) { dbus_free (entry); return NULL; @@ -469,8 +482,8 @@ static void delete_signal (DBusObjectRegistry *registry, DBusSignalEntry *entry) { - _dbus_hash_table_remove_string (registry->signal_table, - entry->name); + _dbus_hash_table_remove_two_strings (registry->signal_table, + entry->name); } static dbus_bool_t @@ -553,11 +566,11 @@ object_remove_from_signals (DBusObjectRegistry *registry, i = 0; while (entry->signals[i] != NULL) { - DBusSignalEntry *iface = entry->signals[i]; + DBusSignalEntry *signal = entry->signals[i]; - signal_entry_remove_object (iface, entry->id_index); - if (iface->n_connections == 0) - delete_signal (registry, iface); + signal_entry_remove_object (signal, entry->id_index); + if (signal->n_connections == 0) + delete_signal (registry, signal); ++i; } } @@ -573,19 +586,24 @@ object_remove_from_signals (DBusObjectRegistry *registry, * * @param registry the object registry * @param object_id object that would like to see the signal - * @param signal signal name + * @param signal_interface signal interface name + * @param signal_name signal member name * * @returns #FALSE if no memory */ dbus_bool_t _dbus_object_registry_connect_locked (DBusObjectRegistry *registry, const DBusObjectID *object_id, + const char *signal_interface, const char *signal_name) { DBusSignalEntry **new_signals; DBusSignalEntry *signal; DBusObjectEntry *entry; int i; + + _dbus_assert (signal_interface != NULL); + _dbus_assert (signal_name != NULL); entry = validate_id (registry, object_id); if (entry == NULL) @@ -617,7 +635,7 @@ _dbus_object_registry_connect_locked (DBusObjectRegistry *registry, entry->signals = new_signals; - signal = lookup_signal (registry, signal_name, TRUE); + signal = lookup_signal (registry, signal_interface, signal_name, TRUE); if (signal == NULL) goto oom; @@ -642,30 +660,35 @@ _dbus_object_registry_connect_locked (DBusObjectRegistry *registry, * * @param registry the object registry * @param object_id object that would like to see the signal - * @param signal signal name + * @param signal_interface signal interface + * @param signal_name signal name */ void _dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry, const DBusObjectID *object_id, + const char *signal_interface, const char *signal_name) { DBusObjectEntry *entry; DBusSignalEntry *signal; + + _dbus_assert (signal_interface != NULL); + _dbus_assert (signal_name != NULL); entry = validate_id (registry, object_id); if (entry == NULL) { - _dbus_warn ("Tried to disconnect signal \"%s\" from a nonexistent D-BUS object ID\n", - signal_name); + _dbus_warn ("Tried to disconnect signal \"%s\"::\"%s\" from a nonexistent D-BUS object ID\n", + signal_interface, signal_name); return; } - signal = lookup_signal (registry, signal_name, FALSE); + signal = lookup_signal (registry, signal_interface, signal_name, FALSE); if (signal == NULL) { - _dbus_warn ("Tried to disconnect signal \"%s\" but no such signal is connected\n", - signal_name); + _dbus_warn ("Tried to disconnect signal \"%s\"::\"%s\" but no such signal is connected\n", + signal_interface, signal_name); return; } @@ -695,7 +718,7 @@ handle_method_call_and_unlock (DBusObjectRegistry *registry, * it to the first object that supports the given interface. */ iface_entry = lookup_interface (registry, - dbus_message_get_name (message), + dbus_message_get_interface (message), FALSE); if (iface_entry == NULL) @@ -750,7 +773,8 @@ handle_signal_and_unlock (DBusObjectRegistry *registry, _dbus_assert (message != NULL); signal_entry = lookup_signal (registry, - dbus_message_get_name (message), + dbus_message_get_interface (message), + dbus_message_get_member (message), FALSE); if (signal_entry == NULL) @@ -1291,7 +1315,8 @@ add_and_remove_objects (DBusObjectRegistry *registry) ++i; } - message = dbus_message_new_method_call ("org.freedesktop.Test.Foo", NULL); + message = dbus_message_new_method_call ("org.freedesktop.Test.Foo", + "Bar", NULL); if (message != NULL) { if (_dbus_object_registry_handle_and_unlock (registry, message) != @@ -1300,7 +1325,8 @@ add_and_remove_objects (DBusObjectRegistry *registry) dbus_message_unref (message); } - message = dbus_message_new_method_call ("org.freedesktop.Test.Blah", NULL); + message = dbus_message_new_method_call ("org.freedesktop.Test.Blah", + "Baz", NULL); if (message != NULL) { if (_dbus_object_registry_handle_and_unlock (registry, message) != @@ -1309,7 +1335,8 @@ add_and_remove_objects (DBusObjectRegistry *registry) dbus_message_unref (message); } - message = dbus_message_new_method_call ("org.freedesktop.Test.NotRegisteredIface", NULL); + message = dbus_message_new_method_call ("org.freedesktop.Test.NotRegisteredIface", + "Boo", NULL); if (message != NULL) { if (_dbus_object_registry_handle_and_unlock (registry, message) != diff --git a/dbus/dbus-object-registry.h b/dbus/dbus-object-registry.h index bcbd0f84..29c92b9c 100644 --- a/dbus/dbus-object-registry.h +++ b/dbus/dbus-object-registry.h @@ -45,10 +45,12 @@ DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry); dbus_bool_t _dbus_object_registry_connect_locked (DBusObjectRegistry *registry, const DBusObjectID *object_id, - const char *signal); + const char *signal_interface, + const char *signal_name); void _dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry, const DBusObjectID *object_id, - const char *signal); + const char *signal_interface, + const char *signal_name); DBUS_END_DECLS; diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index e027cf56..a1f4a722 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -57,7 +57,7 @@ extern "C" { #define DBUS_TYPE_LAST DBUS_TYPE_OBJECT_ID -/* Max length in bytes of a service or message name */ +/* Max length in bytes of a service or interface or member name */ #define DBUS_MAXIMUM_NAME_LENGTH 256 /* Types of message */ @@ -71,14 +71,16 @@ extern "C" { #define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1 /* Header fields */ -#define DBUS_HEADER_FIELD_NAME "name" -#define DBUS_HEADER_FIELD_SERVICE "srvc" -#define DBUS_HEADER_FIELD_REPLY "rply" -#define DBUS_HEADER_FIELD_SENDER "sndr" +#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" /* Services */ -#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" -#define DBUS_SERVICE_BROADCAST "org.freedesktop.DBus.Broadcast" +#define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus" +#define DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST "org.freedesktop.Broadcast" /* Service owner flags */ #define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1 @@ -94,23 +96,30 @@ extern "C" { #define DBUS_ACTIVATION_REPLY_ACTIVATED 0x0 #define DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE 0x1 -/* Messages */ -#define DBUS_MESSAGE_ACTIVATE_SERVICE "org.freedesktop.DBus.ActivateService" -#define DBUS_MESSAGE_SERVICE_EXISTS "org.freedesktop.DBus.ServiceExists" -#define DBUS_MESSAGE_HELLO "org.freedesktop.DBus.Hello" -#define DBUS_MESSAGE_LIST_SERVICES "org.freedesktop.DBus.ListServices" -#define DBUS_MESSAGE_ACQUIRE_SERVICE "org.freedesktop.DBus.AcquireService" -#define DBUS_MESSAGE_SERVICE_ACQUIRED "org.freedesktop.DBus.ServiceAcquired" -#define DBUS_MESSAGE_SERVICE_CREATED "org.freedesktop.DBus.ServiceCreated" -#define DBUS_MESSAGE_SERVICE_DELETED "org.freedesktop.DBus.ServiceDeleted" -#define DBUS_MESSAGE_SERVICE_LOST "org.freedesktop.DBus.ServiceLost" - - -/* This namespace is reserved for locally-synthesized messages, you can't - * send messages that have this namespace. +/* Interfaces, these #define don't do much other than + * catch typos at compile time */ -#define DBUS_NAMESPACE_LOCAL_MESSAGE "org.freedesktop.Local." -#define DBUS_MESSAGE_LOCAL_DISCONNECT DBUS_NAMESPACE_LOCAL_MESSAGE"Disconnect" +#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus" + +/* This is a special interface whose methods can only be invoked + * by the local implementation (messages from remote apps aren't + * allowed to specify this interface). + */ +#define DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL "org.freedesktop.Local" + +#if 0 + /* these are a bad idea, FIXME */ +#define DBUS_METHOD_ORG_FREEDESKTOP_DBUS_ACTIVATE_SERVICE "ActivateService" +#define DBUS_METHOD_ORG_FREEDESKTOP_DBUS_SERVICE_EXISTS "ServiceExists" +#define DBUS_METHOD_ORG_FREEDESKTOP_DBUS_HELLO "Hello" +#define DBUS_METHOD_ORG_FREEDESKTOP_DBUS_LIST_SERVICES "ListServices" +#define DBUS_METHOD_ORG_FREEDESKTOP_DBUS_ACQUIRE_SERVICE "AcquireService" + +#define DBUS_SIGNAL_ORG_FREEDESKTOP_DBUS_SERVICE_ACQUIRED "ServiceAcquired" +#define DBUS_SIGNAL_ORG_FREEDESKTOP_DBUS_SERVICE_CREATED "ServiceCreated" +#define DBUS_SIGNAL_ORG_FREEDESKTOP_DBUS_SERVICE_DELETED "ServiceDeleted" +#define DBUS_SIGNAL_ORG_FREEDESKTOP_DBUS_SERVICE_LOST "ServiceLost" +#endif /* #if 0 */ #ifdef __cplusplus } diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index f4f7a2ad..848135fc 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -2846,7 +2846,7 @@ _dbus_string_validate_nul (const DBusString *str, } /** - * Checks that the given range of the string is a valid message name + * 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 * done separately for now. @@ -2860,9 +2860,9 @@ _dbus_string_validate_nul (const DBusString *str, * @returns #TRUE if the byte range exists and is a valid name */ dbus_bool_t -_dbus_string_validate_name (const DBusString *str, - int start, - int len) +_dbus_string_validate_interface (const DBusString *str, + int start, + int len) { const unsigned char *s; const unsigned char *end; @@ -2902,6 +2902,86 @@ _dbus_string_validate_name (const DBusString *str, return TRUE; } +/** + * Checks that the given range of the string is a valid member 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. + * + * @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_member (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + dbus_bool_t saw_dot; + + 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; + + saw_dot = FALSE; + s = real->str + start; + end = s + len; + while (s != end) + { + if (*s == '.') + { + saw_dot = TRUE; + break; + } + + ++s; + } + + /* No dot allowed in member names */ + if (saw_dot) + return FALSE; + + return TRUE; +} + +/** + * Checks that the given range of the string is a valid error 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. + * + * @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_error_name (const DBusString *str, + int start, + int len) +{ + /* Same restrictions as interface name at the moment */ + return _dbus_string_validate_interface (str, start, len); +} /** * Checks that the given range of the string is a valid service name diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 732359a0..6f164be6 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -223,7 +223,13 @@ 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_name (const DBusString *str, +dbus_bool_t _dbus_string_validate_interface (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_string_validate_member (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_string_validate_error_name (const DBusString *str, int start, int len); dbus_bool_t _dbus_string_validate_service (const DBusString *str, -- cgit