From 3f1ad214b5e5c63697ee208d459b304a4ef6e79b Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 7 Jul 2003 00:47:01 +0000 Subject: 2003-07-06 Havoc Pennington * dbus/dbus-marshal.c (_dbus_marshal_set_object_id): new function (_dbus_marshal_object_id): new (_dbus_demarshal_object_id): new (_dbus_marshal_get_arg_end_pos): support object ID type, and consolidate identical switch cases. Don't conditionalize handling of DBUS_TYPE_UINT64, need to handle the type always. (_dbus_marshal_validate_arg): consolidate identical cases, and handle DBUS_TYPE_OBJECT_ID * dbus/dbus-objectid.c: new file with DBusObjectID data type. * dbus/dbus-protocol.h: add DBUS_TYPE_OBJECT_ID --- dbus/Makefile.am | 2 + dbus/dbus-marshal.c | 157 +++++++++++++++++++++------ dbus/dbus-marshal.h | 28 +++-- dbus/dbus-objectid.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-objectid.h | 61 +++++++++++ dbus/dbus-protocol.h | 5 +- dbus/dbus-test.c | 6 ++ dbus/dbus-test.h | 1 + dbus/dbus-types.h | 8 ++ dbus/dbus.h | 1 + 10 files changed, 517 insertions(+), 44 deletions(-) create mode 100644 dbus/dbus-objectid.c create mode 100644 dbus/dbus-objectid.h (limited to 'dbus') diff --git a/dbus/Makefile.am b/dbus/Makefile.am index eac68c6a..3c3c14e7 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -17,6 +17,7 @@ dbusinclude_HEADERS= \ dbus-memory.h \ dbus-message.h \ dbus-message-handler.h \ + dbus-objectid.h \ dbus-protocol.h \ dbus-server.h \ dbus-threads.h \ @@ -42,6 +43,7 @@ DBUS_LIB_SOURCES= \ dbus-message.c \ dbus-message-handler.c \ dbus-message-internal.h \ + dbus-objectid.c \ dbus-resources.c \ dbus-resources.h \ dbus-server.c \ diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 5d7290e3..2399a282 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -80,6 +80,19 @@ typedef union dbus_uint64_t u; #endif double d; +#ifdef WORDS_BIGENDIAN + struct + { + dbus_uint32_t high; + dbus_uint32_t low; + } bits; +#else + struct + { + dbus_uint32_t low; + dbus_uint32_t high; + } bits; +#endif } DBusOctets8; static DBusOctets8 @@ -423,6 +436,35 @@ _dbus_marshal_set_string (DBusString *str, return TRUE; } +/** + * Sets the existing marshaled object ID at the given offset to a new + * value. The given offset must point to an existing object ID or this + * function doesn't make sense. + * + * @param str the string to write the marshalled string to + * @param offset the byte offset where string should be written + * @param byte_order the byte order to use + * @param value the new value + */ +void +_dbus_marshal_set_object_id (DBusString *str, + int byte_order, + int offset, + const DBusObjectID *value) +{ + DBusOctets8 r; +#ifdef DBUS_HAVE_INT64 + r.u = dbus_object_id_get_as_integer (value); +#else + r.bits.low = dbus_object_id_get_low_bits (value); + r.bits.high = dbus_object_id_get_high_bits (value); +#endif + _dbus_assert (r.bits.low == dbus_object_id_get_low_bits (value)); + _dbus_assert (r.bits.high == dbus_object_id_get_high_bits (value)); + + set_8_octets (str, byte_order, offset, r); +} + static dbus_bool_t marshal_4_octets (DBusString *str, int byte_order, @@ -844,6 +886,32 @@ _dbus_marshal_string_array (DBusString *str, return FALSE; } +/** + * Marshals an object ID value. + * + * @param str the string to append the marshalled value to + * @param byte_order the byte order to use + * @param value the value + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_marshal_object_id (DBusString *str, + int byte_order, + const DBusObjectID *value) +{ + DBusOctets8 r; +#ifdef DBUS_HAVE_INT64 + r.u = dbus_object_id_get_as_integer (value); +#else + r.bits.low = dbus_object_id_get_low_bits (value); + r.bits.high = dbus_object_id_get_high_bits (value); +#endif + _dbus_assert (r.bits.low == dbus_object_id_get_low_bits (value)); + _dbus_assert (r.bits.high == dbus_object_id_get_high_bits (value)); + + return marshal_8_octets (str, byte_order, r); +} + static dbus_uint32_t demarshal_4_octets (const DBusString *str, int byte_order, @@ -1393,6 +1461,36 @@ _dbus_demarshal_string_array (const DBusString *str, return FALSE; } +/** + * Demarshals an object ID. + * + * @param str the string containing the data + * @param byte_order the byte order + * @param pos the position in the string + * @param new_pos the new position of the string + * @param value address to store new object ID + */ +void +_dbus_demarshal_object_id (const DBusString *str, + int byte_order, + int pos, + int *new_pos, + DBusObjectID *value) +{ + DBusOctets8 r; + + r = demarshal_8_octets (str, byte_order, pos, new_pos); + +#ifdef DBUS_HAVE_INT64 + dbus_object_id_set_as_integer (value, r.u); +#else + dbus_object_id_set_low_bits (value, r.bits.low); + dbus_object_id_set_high_bits (value, r.bits.high); +#endif + _dbus_assert (dbus_object_id_get_low_bits (value) == r.bits.low); + _dbus_assert (dbus_object_id_get_high_bits (value) == r.bits.high); +} + /** * Returns the position right after the end of an argument. PERFORMS * NO VALIDATION WHATSOEVER. The message must have been previously @@ -1435,30 +1533,16 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str, break; case DBUS_TYPE_INT32: - *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t); - - break; - case DBUS_TYPE_UINT32: - *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t); - + *end_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4; break; -#ifdef DBUS_HAVE_INT64 case DBUS_TYPE_INT64: - *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int64_t)) + sizeof (dbus_int64_t); - - break; - case DBUS_TYPE_UINT64: - *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint64_t)) + sizeof (dbus_uint64_t); - - break; -#endif /* DBUS_HAVE_INT64 */ - + case DBUS_TYPE_OBJECT_ID: case DBUS_TYPE_DOUBLE: - *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (double)) + sizeof (double); - + + *end_pos = _DBUS_ALIGN_VALUE (pos, 8) + 8; break; case DBUS_TYPE_STRING: @@ -1717,6 +1801,7 @@ validate_array_data (const DBusString *str, case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: + case DBUS_TYPE_OBJECT_ID: /* Call validate arg one time to check alignment padding * at start of array */ @@ -1842,22 +1927,9 @@ _dbus_marshal_validate_arg (const DBusString *str, break; case DBUS_TYPE_INT64: - case DBUS_TYPE_UINT64: - { - int align_8 = _DBUS_ALIGN_VALUE (pos, 8); - - if (!_dbus_string_validate_nul (str, pos, - align_8 - pos)) - { - _dbus_verbose ("int64/uint64 alignment padding not initialized to nul\n"); - return FALSE; - } - - *end_pos = align_8 + 8; - } - break; - + case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: + case DBUS_TYPE_OBJECT_ID: { int align_8 = _DBUS_ALIGN_VALUE (pos, 8); @@ -1866,7 +1938,7 @@ _dbus_marshal_validate_arg (const DBusString *str, if (!_dbus_string_validate_nul (str, pos, align_8 - pos)) { - _dbus_verbose ("double alignment padding not initialized to nul\n"); + _dbus_verbose ("double/int64/uint64/objid alignment padding not initialized to nul\n"); return FALSE; } @@ -2177,6 +2249,7 @@ _dbus_marshal_test (void) #endif char *s; DBusString t; + DBusObjectID obj_id, obj_id2; if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); @@ -2237,6 +2310,22 @@ _dbus_marshal_test (void) if (!(_dbus_demarshal_uint64 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == DBUS_UINT64_CONSTANT (0x123456789abc7))) _dbus_assert_not_reached ("demarshal failed"); #endif /* DBUS_HAVE_INT64 */ + + /* Marshal object IDs */ + dbus_object_id_set_high_bits (&obj_id, 0xfffe); + dbus_object_id_set_low_bits (&obj_id, 0xaacc); + + if (!_dbus_marshal_object_id (&str, DBUS_BIG_ENDIAN, &obj_id)) + _dbus_assert_not_reached ("could not marshal object ID value"); + _dbus_demarshal_object_id (&str, DBUS_BIG_ENDIAN, pos, &pos, &obj_id2); + if (!dbus_object_id_equal (&obj_id, &obj_id2)) + _dbus_assert_not_reached ("demarshal failed"); + + if (!_dbus_marshal_object_id (&str, DBUS_LITTLE_ENDIAN, &obj_id)) + _dbus_assert_not_reached ("could not marshal object ID value"); + _dbus_demarshal_object_id (&str, DBUS_LITTLE_ENDIAN, pos, &pos, &obj_id2); + if (!dbus_object_id_equal (&obj_id, &obj_id2)) + _dbus_assert_not_reached ("demarshal failed"); /* Marshal strings */ tmp1 = "This is the dbus test string"; diff --git a/dbus/dbus-marshal.h b/dbus/dbus-marshal.h index 1eff8995..af18876a 100644 --- a/dbus/dbus-marshal.h +++ b/dbus/dbus-marshal.h @@ -29,6 +29,7 @@ #include #include #include +#include #ifndef PACKAGE #error "config.h not included here" @@ -152,11 +153,16 @@ void _dbus_marshal_set_uint64 (DBusString *str, int offset, dbus_uint64_t value); #endif /* DBUS_HAVE_INT64 */ -dbus_bool_t _dbus_marshal_set_string (DBusString *str, - int byte_order, - int offset, - const DBusString *value, - int len); + +dbus_bool_t _dbus_marshal_set_string (DBusString *str, + int byte_order, + int offset, + const DBusString *value, + int len); +void _dbus_marshal_set_object_id (DBusString *str, + int byte_order, + int offset, + const DBusObjectID *value); dbus_bool_t _dbus_marshal_int32 (DBusString *str, int byte_order, @@ -208,6 +214,10 @@ dbus_bool_t _dbus_marshal_string_array (DBusString *str, int byte_order, const char **value, int len); +dbus_bool_t _dbus_marshal_object_id (DBusString *str, + int byte_order, + const DBusObjectID *value); + double _dbus_demarshal_double (const DBusString *str, int byte_order, int pos, @@ -278,9 +288,11 @@ dbus_bool_t _dbus_demarshal_string_array (const DBusString *str, int *new_pos, char ***array, int *array_len); - - - +void _dbus_demarshal_object_id (const DBusString *str, + int byte_order, + int pos, + int *new_pos, + DBusObjectID *value); dbus_bool_t _dbus_marshal_get_arg_end_pos (const DBusString *str, int byte_order, diff --git a/dbus/dbus-objectid.c b/dbus/dbus-objectid.c new file mode 100644 index 00000000..1fb83e44 --- /dev/null +++ b/dbus/dbus-objectid.c @@ -0,0 +1,292 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-objectid.c DBusObjectID type + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "dbus-objectid.h" +#include "dbus-internals.h" + +#ifdef DBUS_HAVE_INT64 +#define VALUE(objid) ((objid)->dbus_do_not_use_dummy1) +#define HIGH_BITS(objid) ((dbus_uint32_t) (VALUE (obj_id) >> 32)) +#define LOW_BITS(objid) ((dbus_uint32_t) (VALUE (obj_id) & DBUS_UINT64_CONSTANT (0x00000000ffffffff))) +#else +#define HIGH_BITS(objid) ((objid)->dbus_do_not_use_dummy1) +#define LOW_BITS(objid) ((objid)->dbus_do_not_use_dummy2) +#endif + +/** + * @defgroup DBusObjectID object IDs + * @ingroup DBusObjectID + * @brief object ID datatype + * + * Value type representing an object ID, i.e. an object in the remote + * application that can be communicated with. + * + * @{ + */ + +/** + * Checks whether two object IDs have the same value. + * + * @param a the first object ID + * @param b the second object ID + * @returns #TRUE if they are equal + */ +dbus_bool_t +dbus_object_id_equal (const DBusObjectID *a, + const DBusObjectID *b) +{ +#ifdef DBUS_HAVE_INT64 + return VALUE (a) == VALUE (b); +#else + return HIGH_BITS (a) == HIGH_BITS (b) && + LOW_BITS (a) == LOW_BITS (b); +#endif +} + +/** + * Compares two object IDs, appropriate for + * qsort(). Higher/lower IDs have no significance, + * but the comparison can be used for data structures + * that require ordering. + * + * @param a the first object ID + * @param b the second object ID + * @returns -1, 0, 1 as with strcmp() + */ +int +dbus_object_id_compare (const DBusObjectID *a, + const DBusObjectID *b) +{ +#ifdef DBUS_HAVE_INT64 + if (VALUE (a) > VALUE (b)) + return 1; + else if (VALUE (a) < VALUE (b)) + return -1; + else + return 0; +#else + if (HIGH_BITS (a) > HIGH_BITS (b)) + return 1; + else if (HIGH_BITS (a) < HIGH_BITS (b)) + return -1; + else if (LOW_BITS (a) > LOW_BITS (b)) + return 1; + else if (LOW_BITS (a) < LOW_BITS (b)) + return -1; + else + return 0; +#endif +} + +/** + * An object ID contains 64 bits of data. This function + * returns half of those bits. If you are willing to limit + * portability to compilers with a 64-bit type (this includes + * C99 compilers and almost all other compilers) consider + * dbus_object_id_get_as_integer() instead. + * + * @param obj_id the object ID + * @returns the high bits of the ID + * + */ +dbus_uint32_t +dbus_object_id_get_high_bits (const DBusObjectID *obj_id) +{ + return HIGH_BITS (obj_id); +} + +/** + * An object ID contains 64 bits of data. This function + * returns half of those bits. If you are willing to limit + * portability to compilers with a 64-bit type (this includes + * C99 compilers and almost all other compilers) consider + * dbus_object_id_get_as_integer() instead. + * + * @param obj_id the object ID + * @returns the low bits of the ID + * + */ +dbus_uint32_t +dbus_object_id_get_low_bits (const DBusObjectID *obj_id) +{ + return LOW_BITS (obj_id); +} + +/** + * An object ID contains 64 bits of data. This function + * sets half of those bits. If you are willing to limit + * portability to compilers with a 64-bit type (this includes + * C99 compilers and almost all other compilers) consider + * dbus_object_id_set_as_integer() instead. + * + * @param obj_id the object ID + * @param value the new value of the high bits + * + */ +void +dbus_object_id_set_high_bits (DBusObjectID *obj_id, + dbus_uint32_t value) +{ +#ifdef DBUS_HAVE_INT64 + VALUE (obj_id) = (((dbus_uint64_t) value) << 32) | LOW_BITS (obj_id); +#else + HIGH_BITS (obj_id) = value; +#endif +} + +/** + * An object ID contains 64 bits of data. This function + * sets half of those bits. If you are willing to limit + * portability to compilers with a 64-bit type (this includes + * C99 compilers and almost all other compilers) consider + * dbus_object_id_set_as_integer() instead. + * + * @param obj_id the object ID + * @param value the new value of the low bits + * + */ +void +dbus_object_id_set_low_bits (DBusObjectID *obj_id, + dbus_uint32_t value) +{ +#ifdef DBUS_HAVE_INT64 + VALUE (obj_id) = ((dbus_uint64_t) value) | + (((dbus_uint64_t) HIGH_BITS (obj_id)) << 32); +#else + LOW_BITS (obj_id) = value; +#endif +} + +#ifdef DBUS_HAVE_INT64 +/** + * An object ID contains 64 bits of data. This function + * returns all of them as a 64-bit integer. + * + * Use this function only if you are willing to limit portability to + * compilers with a 64-bit type (this includes C99 compilers and + * almost all other compilers). + * + * This function only exists if DBUS_HAVE_INT64 is defined. + * + * @param obj_id the object ID + * @returns the object ID as a 64-bit integer. + */ +dbus_uint64_t +dbus_object_id_get_as_integer (const DBusObjectID *obj_id) +{ + return VALUE (obj_id); +} + +/** + * An object ID contains 64 bits of data. This function sets all of + * them as a 64-bit integer. + * + * Use this function only if you are willing to limit portability to + * compilers with a 64-bit type (this includes C99 compilers and + * almost all other compilers). + * + * This function only exists if #DBUS_HAVE_INT64 is defined. + * + * @param obj_id the object ID + * @param value the new value of the object ID + */ +void +dbus_object_id_set_as_integer (DBusObjectID *obj_id, + dbus_uint64_t value) +{ + VALUE (obj_id) = value; +} +#endif /* DBUS_HAVE_INT64 */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +/** + * Test for object ID routines. + * + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_object_id_test (void) +{ + DBusObjectID tmp; + DBusObjectID tmp2; + + dbus_object_id_set_high_bits (&tmp, 340); + _dbus_assert (dbus_object_id_get_high_bits (&tmp) == 340); + + dbus_object_id_set_low_bits (&tmp, 1492); + _dbus_assert (dbus_object_id_get_low_bits (&tmp) == 1492); + _dbus_assert (dbus_object_id_get_high_bits (&tmp) == 340); + + tmp2 = tmp; + _dbus_assert (dbus_object_id_equal (&tmp, &tmp2)); + +#ifdef DBUS_HAVE_INT64 + _dbus_assert (dbus_object_id_get_as_integer (&tmp) == + ((DBUS_UINT64_CONSTANT (340) << 32) | + DBUS_UINT64_CONSTANT (1492))); + + dbus_object_id_set_as_integer (&tmp, _DBUS_UINT64_MAX); + _dbus_assert (dbus_object_id_get_as_integer (&tmp) == + _DBUS_UINT64_MAX); + _dbus_assert (dbus_object_id_get_high_bits (&tmp) == + _DBUS_UINT_MAX); + _dbus_assert (dbus_object_id_get_low_bits (&tmp) == + _DBUS_UINT_MAX); + + dbus_object_id_set_as_integer (&tmp, 1); + dbus_object_id_set_as_integer (&tmp2, 2); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); + dbus_object_id_set_as_integer (&tmp2, 0); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); + dbus_object_id_set_as_integer (&tmp2, 1); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); +#endif + + tmp2 = tmp; + + dbus_object_id_set_high_bits (&tmp, 1); + dbus_object_id_set_high_bits (&tmp2, 2); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); + dbus_object_id_set_high_bits (&tmp2, 0); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); + dbus_object_id_set_high_bits (&tmp2, 1); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); + + dbus_object_id_set_low_bits (&tmp, 1); + + dbus_object_id_set_low_bits (&tmp2, 2); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); + dbus_object_id_set_low_bits (&tmp2, 0); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); + dbus_object_id_set_low_bits (&tmp2, 1); + _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-objectid.h b/dbus/dbus-objectid.h new file mode 100644 index 00000000..57346910 --- /dev/null +++ b/dbus/dbus-objectid.h @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-objectid.h DBusObjectID type + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_OBJECTID_H +#define DBUS_OBJECTID_H + +#include +#include + +typedef struct DBusObjectID DBusObjectID; + +struct DBusObjectID +{ +#ifdef DBUS_HAVE_INT64 + dbus_uint64_t dbus_do_not_use_dummy1; +#else + dbus_uint32_t dbus_do_not_use_dummy1; + dbus_uint32_t dbus_do_not_use_dummy2; +#endif +}; + +dbus_bool_t dbus_object_id_equal (const DBusObjectID *a, + const DBusObjectID *b); +int dbus_object_id_compare (const DBusObjectID *a, + const DBusObjectID *b); +dbus_uint32_t dbus_object_id_get_high_bits (const DBusObjectID *obj_id); +dbus_uint32_t dbus_object_id_get_low_bits (const DBusObjectID *obj_id); +void dbus_object_id_set_high_bits (DBusObjectID *obj_id, + dbus_uint32_t value); +void dbus_object_id_set_low_bits (DBusObjectID *obj_id, + dbus_uint32_t value); +#ifdef DBUS_HAVE_INT64 +dbus_uint64_t dbus_object_id_get_as_integer (const DBusObjectID *obj_id); +void dbus_object_id_set_as_integer (DBusObjectID *obj_id, + dbus_uint64_t value); +#endif + +#endif /* DBUS_OBJECTID_H */ diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index fbdcb6dd..82bb6e3c 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -53,8 +53,9 @@ extern "C" { #define DBUS_TYPE_NAMED 10 #define DBUS_TYPE_ARRAY 11 #define DBUS_TYPE_DICT 12 - -#define DBUS_TYPE_LAST DBUS_TYPE_DICT +#define DBUS_TYPE_OBJECT_ID 13 + +#define DBUS_TYPE_LAST DBUS_TYPE_OBJECT_ID /* Max length in bytes of a service or message name */ #define DBUS_MAXIMUM_NAME_LENGTH 256 diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 2fbab5a4..3d5d14bb 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -99,6 +99,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) die ("address parsing"); check_memleaks (); + + printf ("%s: running object ID tests\n", "dbus-test"); + if (!_dbus_object_id_test ()) + die ("object ID"); + + check_memleaks (); printf ("%s: running marshalling tests\n", "dbus-test"); if (!_dbus_marshal_test ()) diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index 22a43f79..512cb9a6 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -53,6 +53,7 @@ dbus_bool_t _dbus_sysdeps_test (void); dbus_bool_t _dbus_spawn_test (const char *test_data_dir); dbus_bool_t _dbus_userdb_test (const char *test_data_dir); dbus_bool_t _dbus_memory_test (void); +dbus_bool_t _dbus_object_id_test (void); void dbus_internal_do_not_use_run_tests (const char *test_data_dir); diff --git a/dbus/dbus-types.h b/dbus/dbus-types.h index 854b6526..99cb45f5 100644 --- a/dbus/dbus-types.h +++ b/dbus/dbus-types.h @@ -83,6 +83,10 @@ typedef dbus_uint32_t dbus_unichar_t; * * A 64-bit unsigned integer on all platforms that support it. * If supported, #DBUS_HAVE_INT64 will be defined. + * + * C99 requires a 64-bit type and most likely all interesting + * compilers support one. GLib for example flat-out requires + * a 64-bit type. */ /** @@ -90,6 +94,10 @@ typedef dbus_uint32_t dbus_unichar_t; * * A 64-bit signed integer on all platforms that support it. * If supported, #DBUS_HAVE_INT64 will be defined. + * + * C99 requires a 64-bit type and most likely all interesting + * compilers support one. GLib for example flat-out requires + * a 64-bit type. */ /** diff --git a/dbus/dbus.h b/dbus/dbus.h index 0dd072ac..38db4f5b 100644 --- a/dbus/dbus.h +++ b/dbus/dbus.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include -- cgit From d8abf955f5bff3e83cabd267883039f7a42c98c3 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 8 Jul 2003 05:07:32 +0000 Subject: 2003-07-08 Havoc Pennington * dbus/dbus-object.h: sketch out an API for registering objects with a connection, that allows us to use as little as 24 bytes per object and lets application code represent an object in any conceivable way. * dbus/dbus-object-registry.c: implement the hard bits of the DBusConnection aspect of object API. Not yet wired up. --- dbus/Makefile.am | 4 + dbus/dbus-connection-internal.h | 1 + dbus/dbus-connection.c | 16 ++ dbus/dbus-connection.h | 1 + dbus/dbus-object-registry.c | 325 ++++++++++++++++++++++++++++++++++++++++ dbus/dbus-object-registry.h | 50 +++++++ dbus/dbus-object.c | 27 ++++ dbus/dbus-object.h | 85 +++++++++++ dbus/dbus-objectid.h | 4 + dbus/dbus-test.c | 6 + dbus/dbus-test.h | 1 + dbus/dbus.h | 1 + 12 files changed, 521 insertions(+) create mode 100644 dbus/dbus-object-registry.c create mode 100644 dbus/dbus-object-registry.h create mode 100644 dbus/dbus-object.c create mode 100644 dbus/dbus-object.h (limited to 'dbus') diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 3c3c14e7..8c919f31 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -17,6 +17,7 @@ dbusinclude_HEADERS= \ dbus-memory.h \ dbus-message.h \ dbus-message-handler.h \ + dbus-object.h \ dbus-objectid.h \ dbus-protocol.h \ dbus-server.h \ @@ -43,7 +44,10 @@ DBUS_LIB_SOURCES= \ dbus-message.c \ dbus-message-handler.c \ dbus-message-internal.h \ + dbus-object.c \ dbus-objectid.c \ + dbus-object-registry.c \ + dbus-object-registry.h \ dbus-resources.c \ dbus-resources.h \ dbus-server.c \ diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 5ddc0e0a..eaa35955 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -81,6 +81,7 @@ void _dbus_message_handler_remove_connection (DBusMessageHandl DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandler *handler, DBusConnection *connection, DBusMessage *message); +dbus_uint32_t _dbus_connection_get_id (DBusConnection *connection); DBUS_END_DECLS; diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 01b2a7bf..237c195b 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -920,6 +920,22 @@ _dbus_connection_handle_watch (DBusWatch *watch, return retval; } +/** + * Get the ID to be used in the high bits of an object ID for an object + * registered with this connection. + * + * @todo implement this function + * + * @param connection the connection. + * @returns the connection portion of the object ID + */ +dbus_uint32_t +_dbus_connection_get_id (DBusConnection *connection) +{ + /* FIXME */ + return 1492; +} + /** @} */ /** diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 9f4dd7ae..ce57c98d 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -37,6 +37,7 @@ typedef struct DBusConnection DBusConnection; typedef struct DBusWatch DBusWatch; typedef struct DBusTimeout DBusTimeout; typedef struct DBusMessageHandler DBusMessageHandler; +typedef struct DBusObject DBusObject; typedef struct DBusPreallocatedSend DBusPreallocatedSend; typedef enum diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c new file mode 100644 index 00000000..9f7ca3ff --- /dev/null +++ b/dbus/dbus-object-registry.c @@ -0,0 +1,325 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object-registry.c DBusObjectRegistry (internals of DBusConnection) + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "dbus-object-registry.h" +#include "dbus-connection-internal.h" +#include "dbus-internals.h" +#include + +/** + * @defgroup DBusObjectRegistry Map object IDs to implementations + * @ingroup DBusInternals + * @brief DBusObjectRegistry is used by DBusConnection to track object IDs + * + * Types and functions related to DBusObjectRegistry + * + * @{ + */ + +typedef struct DBusObjectEntry DBusObjectEntry; + + /* 14 bits for object index, 32K objects */ +#define DBUS_OBJECT_INDEX_BITS (14) +#define DBUS_OBJECT_INDEX_MASK (0x7fff) +#define DBUS_MAX_OBJECTS_PER_CONNECTION DBUS_OBJECT_INDEX_MASK +struct DBusObjectEntry +{ + unsigned int id_index : 14; /**< Index of this entry in the entries array */ + unsigned int id_times_used : 18; /**< Count of times entry has been used; avoids recycling IDs too often */ + + void *object_impl; /**< Pointer to application-supplied implementation */ + const DBusObjectVTable *vtable; /**< Virtual table for this object */ +}; + +struct DBusObjectRegistry +{ + int refcount; + DBusConnection *connection; + + DBusObjectEntry *entries; + int n_entries_allocated; + int n_entries_used; +}; + +DBusObjectRegistry* +_dbus_object_registry_new (DBusConnection *connection) +{ + DBusObjectRegistry *registry; + + registry = dbus_new0 (DBusObjectRegistry, 1); + + registry->refcount = 1; + registry->connection = connection; + + return registry; +} + +void +_dbus_object_registry_ref (DBusObjectRegistry *registry) +{ + _dbus_assert (registry->refcount > 0); + + registry->refcount += 1; +} + +void +_dbus_object_registry_unref (DBusObjectRegistry *registry) +{ + _dbus_assert (registry->refcount > 0); + + registry->refcount -= 1; + + if (registry->refcount == 0) + { + _dbus_assert (registry->n_entries_used == 0); + + dbus_free (registry->entries); + dbus_free (registry); + } +} + +#define ENTRY_TO_ID(entry) \ + (((dbus_uint32_t) (entry)->id_index) | \ + (((dbus_uint32_t)(entry)->id_times_used) << DBUS_OBJECT_INDEX_BITS)) + +#define ID_TO_INDEX(id) \ + (((dbus_uint32_t) (id)) | DBUS_OBJECT_INDEX_MASK) + +#define ID_TO_TIMES_USED(id) \ + (((dbus_uint32_t) (id)) >> DBUS_OBJECT_INDEX_BITS) + +static DBusObjectEntry* +validate_id (DBusObjectRegistry *registry, + const DBusObjectID *object_id) +{ + int idx; + int times_used; + dbus_uint32_t low_bits; + + low_bits = dbus_object_id_get_low_bits (object_id); + + idx = ID_TO_INDEX (low_bits); + times_used = ID_TO_TIMES_USED (low_bits); + + if (idx >= registry->n_entries_allocated) + return NULL; + if (registry->entries[idx].vtable == NULL) + return NULL; + if (registry->entries[idx].id_times_used != times_used) + return NULL; + _dbus_assert (registry->entries[idx].id_index == idx); + _dbus_assert (registry->n_entries_used > 0); + + return ®istry->entries[idx]; +} + +static void +info_from_entry (DBusObjectRegistry *registry, + DBusObjectInfo *info, + DBusObjectEntry *entry) +{ + info->connection = registry->connection; + info->object_impl = entry->object_impl; + dbus_object_id_set_high_bits (&info->object_id, + _dbus_connection_get_id (registry->connection)); + dbus_object_id_set_low_bits (&info->object_id, + ENTRY_TO_ID (entry)); +} + +dbus_bool_t +_dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id) +{ + int i; + DBusObjectInfo info; + + if (registry->n_entries_used == registry->n_entries_allocated) + { + DBusObjectEntry *new_entries; + int new_alloc; + + if (registry->n_entries_allocated == 0) + new_alloc = 16; + else + { + if (registry->n_entries_allocated == DBUS_MAX_OBJECTS_PER_CONNECTION) + { + _dbus_warn ("Attempting to register a new D-BUS object, but maximum object count of %d reached\n", + DBUS_MAX_OBJECTS_PER_CONNECTION); + return FALSE; + } + + new_alloc = registry->n_entries_allocated * 2; + if (new_alloc > DBUS_MAX_OBJECTS_PER_CONNECTION) + new_alloc = DBUS_MAX_OBJECTS_PER_CONNECTION; + } + + new_entries = dbus_realloc (registry->entries, + new_alloc * sizeof (DBusObjectEntry)); + + if (new_entries == NULL) + return FALSE; + + memset (&new_entries[registry->n_entries_allocated], + '\0', + sizeof (DBusObjectEntry) * (new_alloc - registry->n_entries_allocated)); + + registry->entries = new_entries; + registry->n_entries_allocated = new_alloc; + } + _dbus_assert (registry->n_entries_used < registry->n_entries_allocated); + + /* We linear search for an available entry. However, short-circuit + * the hopefully-common situation where we don't have a sparse + * array. + */ + if (registry->entries[registry->n_entries_used].vtable == NULL) + { + i = registry->n_entries_used; + } + else + { + /* If we do have a sparse array, we try to get rid of it rather + * than using empty slots on the end, so we won't hit this case + * next time. + */ + + /* If index n_entries_used is occupied, then + * there is at least one entry outside of + * the range [0, n_entries_used). Thus, there is + * at least one blank entry inside that range. + */ + i = 0; + while (i < registry->n_entries_used) + { + if (registry->entries[i].vtable == NULL) + break; + ++i; + } + + _dbus_assert (i < registry->n_entries_used); + } + + registry->entries[i].id_index = i; + /* Overflow is OK here */ + registry->entries[i].id_times_used += 1; + + registry->entries[i].vtable = vtable; + registry->entries[i].object_impl = object_impl; + + info_from_entry (registry, &info, ®istry->entries[i]); + + /* Drop lock and invoke application code */ + _dbus_connection_unlock (registry->connection); + + (* vtable->registered) (&info); + + return TRUE; +} + +void +_dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, + const DBusObjectID *object_id) +{ + DBusObjectInfo info; + DBusObjectEntry *entry; + const DBusObjectVTable *vtable; + + entry = validate_id (registry, object_id); + if (entry == NULL) + { + _dbus_warn ("Tried to unregister a nonexistent D-BUS object ID\n"); + return; + } + + info_from_entry (registry, &info, entry); + vtable = entry->vtable; + entry->vtable = NULL; + entry->object_impl = NULL; + registry->n_entries_used -= 1; + + /* Drop lock and invoke application code */ + _dbus_connection_unlock (registry->connection); + + (* vtable->unregistered) (&info); +} + +void +_dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + /* FIXME */ +} + +void +_dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) +{ + int i; + + i = 0; + while (registry->n_entries_used > 0) + { + _dbus_assert (i < registry->n_entries_allocated); + if (registry->entries[i].vtable != NULL) + { + DBusObjectInfo info; + const DBusObjectVTable *vtable; + + info_from_entry (registry, &info, ®istry->entries[i]); + vtable = registry->entries[i].vtable; + registry->entries[i].vtable = NULL; + registry->entries[i].object_impl = NULL; + registry->n_entries_used -= 1; + _dbus_assert (registry->n_entries_used >= 0); + + (* vtable->unregistered) (&info); + } + + ++i; + } + + _dbus_assert (registry->n_entries_used == 0); +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +/** + * @ingroup DBusObjectRegistry + * Unit test for DBusObjectRegistry + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_object_registry_test (void) +{ + + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-object-registry.h b/dbus/dbus-object-registry.h new file mode 100644 index 00000000..d33664e5 --- /dev/null +++ b/dbus/dbus-object-registry.h @@ -0,0 +1,50 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object-registry.h DBusObjectRegistry (internals of DBusConnection) + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_OBJECT_REGISTRY_H +#define DBUS_OBJECT_REGISTRY_H + +#include + +DBUS_BEGIN_DECLS; + +typedef struct DBusObjectRegistry DBusObjectRegistry; + +DBusObjectRegistry* _dbus_object_registry_new (DBusConnection *connection); +void _dbus_object_registry_ref (DBusObjectRegistry *registry); +void _dbus_object_registry_unref (DBusObjectRegistry *registry); + +dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id); +void _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, + const DBusObjectID *object_id); +void _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message); +void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry); + + +DBUS_END_DECLS; + +#endif /* DBUS_OBJECT_REGISTRY_H */ diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c new file mode 100644 index 00000000..fdd33dd4 --- /dev/null +++ b/dbus/dbus-object.c @@ -0,0 +1,27 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object.c DBusObject type + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "dbus-internals.h" +#include "dbus-object.h" + diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h new file mode 100644 index 00000000..0c92776d --- /dev/null +++ b/dbus/dbus-object.h @@ -0,0 +1,85 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object.h DBusObject type + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_OBJECT_H +#define DBUS_OBJECT_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS; + +typedef struct DBusObjectVTable DBusObjectVTable; +typedef struct DBusObjectInfo DBusObjectInfo; +typedef struct DBusCallbackObject DBusCallbackObject; + +struct DBusObjectInfo +{ + void *object_impl; + DBusObjectID object_id; + DBusConnection *connection; +}; + +typedef void (* DBusObjectRegisteredFunction) (DBusObjectInfo *info); +typedef void (* DBusObjectUnregisteredFunction) (DBusObjectInfo *info); +typedef void (* DBusObjectMessageFunction) (DBusObjectInfo *info, + DBusMessage *message); + +struct DBusObjectVTable +{ + DBusObjectRegisteredFunction registered; + DBusObjectUnregisteredFunction unregistered; + DBusObjectMessageFunction message; +}; + +dbus_bool_t dbus_connection_register_object (DBusConnection *connection, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id); +void dbus_connection_unregister_object (DBusConnection *connection, + const DBusObjectID *object_id); + +extern const DBusObjectVTable *dbus_callback_object_vtable; + +DBusCallbackObject* dbus_callback_object_new (DBusObjectMessageFunction function, + void *user_data, + DBusFreeFunction free_user_data); +void dbus_callback_object_ref (DBusCallbackObject *handler); +void dbus_callback_object_unref (DBusCallbackObject *handler); +void* dbus_callback_object_get_data (DBusCallbackObject *handler); +void dbus_callback_object_set_data (DBusCallbackObject *handler, + void *data, + DBusFreeFunction free_user_data); +void dbus_callback_object_set_function (DBusCallbackObject *handler, + DBusObjectMessageFunction function); + + +DBUS_END_DECLS; + +#endif /* DBUS_OBJECT_H */ diff --git a/dbus/dbus-objectid.h b/dbus/dbus-objectid.h index 57346910..b5e1f606 100644 --- a/dbus/dbus-objectid.h +++ b/dbus/dbus-objectid.h @@ -30,6 +30,8 @@ #include #include +DBUS_BEGIN_DECLS; + typedef struct DBusObjectID DBusObjectID; struct DBusObjectID @@ -58,4 +60,6 @@ void dbus_object_id_set_as_integer (DBusObjectID *obj_id dbus_uint64_t value); #endif +DBUS_END_DECLS; + #endif /* DBUS_OBJECTID_H */ diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 3d5d14bb..220961c7 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -105,6 +105,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) die ("object ID"); check_memleaks (); + + printf ("%s: running object registry tests\n", "dbus-test"); + if (!_dbus_object_registry_test ()) + die ("object registry"); + + check_memleaks (); printf ("%s: running marshalling tests\n", "dbus-test"); if (!_dbus_marshal_test ()) diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index 512cb9a6..c9555e2d 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -54,6 +54,7 @@ dbus_bool_t _dbus_spawn_test (const char *test_data_dir); dbus_bool_t _dbus_userdb_test (const char *test_data_dir); dbus_bool_t _dbus_memory_test (void); dbus_bool_t _dbus_object_id_test (void); +dbus_bool_t _dbus_object_registry_test (void); void dbus_internal_do_not_use_run_tests (const char *test_data_dir); diff --git a/dbus/dbus.h b/dbus/dbus.h index 38db4f5b..d83a4a50 100644 --- a/dbus/dbus.h +++ b/dbus/dbus.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include -- cgit From 824d4a5edfe1fa7222ab5cb49928bf78a675b563 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 9 Jul 2003 03:41:00 +0000 Subject: 2003-07-08 Havoc Pennington * dbus/dbus-object.c: implement some of this * dbus/dbus-object-registry.c (_dbus_object_registry_add_and_unlock): fill in the object_id out param (_dbus_object_registry_new): handle OOM --- dbus/dbus-connection.c | 45 ++++++ dbus/dbus-connection.h | 13 +- dbus/dbus-internals.h | 3 +- dbus/dbus-message-handler.c | 2 +- dbus/dbus-message.h | 1 + dbus/dbus-object-registry.c | 12 +- dbus/dbus-object.c | 324 +++++++++++++++++++++++++++++++++++++++++++- dbus/dbus-object.h | 25 ++-- dbus/dbus-test.c | 6 + dbus/dbus-test.h | 1 + dbus/dbus-threads.c | 1 + 11 files changed, 406 insertions(+), 27 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 237c195b..ed29edc9 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2942,6 +2942,51 @@ dbus_connection_unregister_handler (DBusConnection *connection, CONNECTION_UNLOCK (connection); } +/** + * Registers an object with the connection. This object is assigned an + * object ID, and will be visible under this ID and with the provided + * interfaces to the peer application on the other end of the + * connection. The object instance should be passed in as object_impl; + * the instance can be any datatype, as long as it fits in a void*. + * + * As a side effect of calling this function, the "registered" + * callback in the #DBusObjectVTable will be invoked. + * + * @param connection the connection to register the instance with + * @param interfaces #NULL-terminated array of interface names the instance supports + * @param vtable virtual table of functions for manipulating the instance + * @param object_impl object instance + * @param object_id if non-#NULL, object ID to initialize with the new object's ID + * @returns #FALSE if not enough memory to register the object instance + */ +dbus_bool_t +dbus_connection_register_object (DBusConnection *connection, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id) +{ + + return FALSE; +} + +/** + * Reverses the effects of dbus_connection_register_object(), + * and invokes the "unregistered" callback in the #DBusObjectVTable + * for the given object. The passed-in object ID must be a valid, + * registered object ID or the results are undefined. + * + * @param connection the connection to unregister the object ID from + * @param object_id the object ID to unregister + */ +void +dbus_connection_unregister_object (DBusConnection *connection, + const DBusObjectID *object_id) +{ + + +} + static DBusDataSlotAllocator slot_allocator; _DBUS_DEFINE_GLOBAL_LOCK (connection_slots); diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index ce57c98d..6c0da920 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -28,12 +28,11 @@ #define DBUS_CONNECTION_H #include -#include #include +#include DBUS_BEGIN_DECLS; -typedef struct DBusConnection DBusConnection; typedef struct DBusWatch DBusWatch; typedef struct DBusTimeout DBusTimeout; typedef struct DBusMessageHandler DBusMessageHandler; @@ -172,7 +171,17 @@ void dbus_connection_unregister_handler (DBusConnection *connection, const char **messages_to_handle, int n_messages); +/* Objects */ +dbus_bool_t dbus_connection_register_object (DBusConnection *connection, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id); +void dbus_connection_unregister_object (DBusConnection *connection, + const DBusObjectID *object_id); + +/* Other */ dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p); void dbus_connection_free_data_slot (dbus_int32_t *slot_p); dbus_bool_t dbus_connection_set_data (DBusConnection *connection, diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index d84017d7..7acda71a 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -232,10 +232,11 @@ _DBUS_DECLARE_GLOBAL_LOCK (server_slots); _DBUS_DECLARE_GLOBAL_LOCK (message_slots); _DBUS_DECLARE_GLOBAL_LOCK (atomic); _DBUS_DECLARE_GLOBAL_LOCK (message_handler); +_DBUS_DECLARE_GLOBAL_LOCK (callback_object); _DBUS_DECLARE_GLOBAL_LOCK (bus); _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); _DBUS_DECLARE_GLOBAL_LOCK (system_users); -#define _DBUS_N_GLOBAL_LOCKS (9) +#define _DBUS_N_GLOBAL_LOCKS (10) dbus_bool_t _dbus_threads_init_debug (void); diff --git a/dbus/dbus-message-handler.c b/dbus/dbus-message-handler.c index f38e5100..8bb4dd18 100644 --- a/dbus/dbus-message-handler.c +++ b/dbus/dbus-message-handler.c @@ -325,7 +325,7 @@ free_test_data (void *data) } /** - * @ingroup DBusMessageInternals + * @ingroup DBusMessageHandlerInternals * Unit test for DBusMessageHandler. * * @returns #TRUE on success. diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index 9f07565c..bd52bd1a 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -31,6 +31,7 @@ #include #include #include +#include #include DBUS_BEGIN_DECLS; diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index 9f7ca3ff..eba2d8fb 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -66,7 +66,9 @@ _dbus_object_registry_new (DBusConnection *connection) DBusObjectRegistry *registry; registry = dbus_new0 (DBusObjectRegistry, 1); - + if (registry == NULL) + return NULL; + registry->refcount = 1; registry->connection = connection; @@ -230,7 +232,9 @@ _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, registry->entries[i].object_impl = object_impl; info_from_entry (registry, &info, ®istry->entries[i]); - + if (object_id) + *object_id = info.object_id; + /* Drop lock and invoke application code */ _dbus_connection_unlock (registry->connection); @@ -317,8 +321,8 @@ _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) dbus_bool_t _dbus_object_registry_test (void) { - - + /* FIXME */ + return TRUE; } diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c index fdd33dd4..262f75ca 100644 --- a/dbus/dbus-object.c +++ b/dbus/dbus-object.c @@ -1,10 +1,10 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-object.c DBusObject type +/* dbus-object.c Objects * * Copyright (C) 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -14,7 +14,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -25,3 +25,321 @@ #include "dbus-internals.h" #include "dbus-object.h" +/** + * @defgroup DBusCallbackObjectInternals DBusCallbackObject implementation details + * @ingroup DBusInternals + * @brief DBusCallbackObject private implementation details. + * + * The guts of DBusCallbackObject and its methods. + * + * @{ + */ + +_DBUS_DEFINE_GLOBAL_LOCK (callback_object); + +/** + * @brief Internals of DBusCallbackObject + * + * Object that can send and receive messages. + */ +struct DBusCallbackObject +{ + DBusAtomic refcount; /**< reference count */ + DBusObjectMessageFunction function; /**< callback function */ + void *user_data; /**< user data for function */ + DBusFreeFunction free_user_data; /**< free the user data */ +}; + +static void +callback_object_registered (DBusObjectInfo *info) +{ + DBusCallbackObject *callback = info->object_impl; + + dbus_callback_object_ref (callback); +} + +static void +callback_object_unregistered (DBusObjectInfo *info) +{ + DBusCallbackObject *callback = info->object_impl; + + dbus_callback_object_unref (callback); +} + +static void +callback_object_message (DBusObjectInfo *info, + DBusMessage *message) +{ + DBusCallbackObject *callback = info->object_impl; + + if (callback->function) + (* callback->function) (info, message); +} + +/** @} */ + +/** + * @defgroup DBusObject DBusObjectInfo, DBusObjectVTable, DBusCallbackObject + * @ingroup DBus + * @brief support for object instances + * + * Behind each DBusConnection are object instances. An object instance + * may be a GObject (using GLib), a QObject (using Qt), a built-in + * object type called DBusCallbackObject, or any other representation + * of an object; it's even permissible to have an object that's simply + * an integer value or a pointer to a struct. + * + * Objects are registered with one or more DBusConnection. Registered + * objects receive an object ID, represented by the DBusObjectID type. + * Object IDs can be passed over a DBusConnection and used by the + * remote application to refer to objects. Remote applications can + * also refer to objects by dynamically locating objects that support + * a particular interface. + * + * To define an object, you simply provide three callbacks: one to be + * called when the object is registered with a new connection, one + * to be called when the object is unregistered, and one to be called + * when the object receives a message from the peer on the other end + * of the DBusConnection. The three callbacks are specified in a + * DBusObjectVTable struct. + * + * The DBusObjectInfo struct is used to pass the object pointer + * (object_impl), connection, and object ID to each of the callbacks + * in the virtual table. This struct should be treated as read-only. + * + * DBusCallbackObject is provided for convenience as a way to + * implement an object quickly by writing only one callback function, + * the callback that processes messages. To use DBusCallbackObject, + * simply create one, then call dbus_connection_register_object() + * passing in the provided DBusObjectVTable + * dbus_callback_object_vtable. This is the simplest possible object; + * it simply contains a function to be called whenever a message is + * received. + * + * The DBusCallbackObject will be strong-referenced by the + * DBusConnection, so may be unreferenced once it's registered, and + * will go away either on unregistration or when the connection is + * freed. + * + * One DBusCallbackObject may be registered with any number of + * DBusConnection. + * + * @{ + */ + +/** + * @typedef DBusCallbackObject + * + * Opaque data type representing a callback object. + */ + +static const DBusObjectVTable callback_object_vtable = { + callback_object_registered, + callback_object_unregistered, + callback_object_message +}; + +/** + * Virtual table for a DBusCallbackObject, used to register the + * callback object with dbus_connection_register_object(). + */ +const DBusObjectVTable* dbus_callback_object_vtable = &callback_object_vtable; + +/** + * Creates a new callback object. The callback function + * may be #NULL for a no-op callback or a callback to + * be assigned a function later. + * + * Use dbus_connection_register_object() along with + * dbus_callback_object_vtable to register the callback object with + * one or more connections. Each connection will add a reference to + * the callback object, so once it's registered it may be unreferenced + * with dbus_callback_object_unref(). + * + * @param function function to call to handle a message + * @param user_data data to pass to the function + * @param free_user_data function to call to free the user data + * @returns a new DBusCallbackObject or #NULL if no memory. + */ +DBusCallbackObject* +dbus_callback_object_new (DBusObjectMessageFunction function, + void *user_data, + DBusFreeFunction free_user_data) +{ + DBusCallbackObject *callback; + + callback = dbus_new0 (DBusCallbackObject, 1); + if (callback == NULL) + return NULL; + + callback->refcount.value = 1; + callback->function = function; + callback->user_data = user_data; + callback->free_user_data = free_user_data; + + return callback; +} + +/** + * Increments the reference count on a callback object. + * + * @param callback the callback + */ +void +dbus_callback_object_ref (DBusCallbackObject *callback) +{ + _dbus_return_if_fail (callback != NULL); + + _dbus_atomic_inc (&callback->refcount); +} + + +/** + * Decrements the reference count on a callback object, + * freeing the callback if the count reaches 0. + * + * @param callback the callback + */ +void +dbus_callback_object_unref (DBusCallbackObject *callback) +{ + dbus_bool_t last_unref; + + _dbus_return_if_fail (callback != NULL); + + last_unref = (_dbus_atomic_dec (&callback->refcount) == 1); + + if (last_unref) + { + if (callback->free_user_data) + (* callback->free_user_data) (callback->user_data); + + dbus_free (callback); + } +} + +/** + * Gets the user data for the callback. + * + * @param callback the callback + * @returns the user data + */ +void* +dbus_callback_object_get_data (DBusCallbackObject *callback) +{ + void* user_data; + + _dbus_return_val_if_fail (callback != NULL, NULL); + + _DBUS_LOCK (callback_object); + user_data = callback->user_data; + _DBUS_UNLOCK (callback_object); + return user_data; +} + + +/** + * Sets the user data for the callback. Frees any previously-existing + * user data with the previous free_user_data function. + * + * @param callback the callback + * @param user_data the user data + * @param free_user_data free function for the data + */ +void +dbus_callback_object_set_data (DBusCallbackObject *callback, + void *user_data, + DBusFreeFunction free_user_data) +{ + DBusFreeFunction old_free_func; + void *old_user_data; + + _dbus_return_if_fail (callback != NULL); + + _DBUS_LOCK (callback_object); + old_free_func = callback->free_user_data; + old_user_data = callback->user_data; + + callback->user_data = user_data; + callback->free_user_data = free_user_data; + _DBUS_UNLOCK (callback_object); + + if (old_free_func) + (* old_free_func) (old_user_data); +} + +/** + * Sets the function to be used to handle messages to the + * callback object. + * + * @param callback the callback + * @param function the function + */ +void +dbus_callback_object_set_function (DBusCallbackObject *callback, + DBusObjectMessageFunction function) +{ + _dbus_return_if_fail (callback != NULL); + + _DBUS_LOCK (callback_object); + callback->function = function; + _DBUS_UNLOCK (callback_object); +} + + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +static void +test_message_function (DBusObjectInfo *info, + DBusMessage *message) +{ + /* nothing */ +} + +static void +free_test_data (void *data) +{ + /* does nothing */ +} + +/** + * @ingroup DBusCallbackObjectInternals + * Unit test for DBusCallbackObject. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_object_test (void) +{ + DBusCallbackObject *callback; + +#define TEST_DATA ((void*) 0xcafebabe) + + callback = dbus_callback_object_new (test_message_function, + TEST_DATA, + free_test_data); + + _dbus_assert (callback != NULL); + _dbus_assert (callback->function == test_message_function); + + if (dbus_callback_object_get_data (callback) != TEST_DATA) + _dbus_assert_not_reached ("got wrong data"); + + dbus_callback_object_set_data (callback, NULL, NULL); + if (dbus_callback_object_get_data (callback) != NULL) + _dbus_assert_not_reached ("got wrong data after set"); + + dbus_callback_object_set_function (callback, NULL); + _dbus_assert (callback->function == NULL); + + dbus_callback_object_ref (callback); + dbus_callback_object_unref (callback); + dbus_callback_object_unref (callback); + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h index 0c92776d..b05d9c4b 100644 --- a/dbus/dbus-object.h +++ b/dbus/dbus-object.h @@ -1,5 +1,5 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-object.h DBusObject type +/* dbus-object.h Objects * * Copyright (C) 2003 Red Hat Inc. * @@ -29,18 +29,19 @@ #include #include +#include #include -#include DBUS_BEGIN_DECLS; +typedef struct DBusConnection DBusConnection; typedef struct DBusObjectVTable DBusObjectVTable; typedef struct DBusObjectInfo DBusObjectInfo; typedef struct DBusCallbackObject DBusCallbackObject; struct DBusObjectInfo { - void *object_impl; + void *object_impl; /**< Object information */ DBusObjectID object_id; DBusConnection *connection; }; @@ -57,26 +58,18 @@ struct DBusObjectVTable DBusObjectMessageFunction message; }; -dbus_bool_t dbus_connection_register_object (DBusConnection *connection, - const char **interfaces, - const DBusObjectVTable *vtable, - void *object_impl, - DBusObjectID *object_id); -void dbus_connection_unregister_object (DBusConnection *connection, - const DBusObjectID *object_id); - extern const DBusObjectVTable *dbus_callback_object_vtable; DBusCallbackObject* dbus_callback_object_new (DBusObjectMessageFunction function, void *user_data, DBusFreeFunction free_user_data); -void dbus_callback_object_ref (DBusCallbackObject *handler); -void dbus_callback_object_unref (DBusCallbackObject *handler); -void* dbus_callback_object_get_data (DBusCallbackObject *handler); -void dbus_callback_object_set_data (DBusCallbackObject *handler, +void dbus_callback_object_ref (DBusCallbackObject *callback); +void dbus_callback_object_unref (DBusCallbackObject *callback); +void* dbus_callback_object_get_data (DBusCallbackObject *callback); +void dbus_callback_object_set_data (DBusCallbackObject *callback, void *data, DBusFreeFunction free_user_data); -void dbus_callback_object_set_function (DBusCallbackObject *handler, +void dbus_callback_object_set_function (DBusCallbackObject *callback, DBusObjectMessageFunction function); diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 220961c7..c3b31107 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -111,6 +111,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) die ("object registry"); check_memleaks (); + + printf ("%s: running object tests\n", "dbus-test"); + if (!_dbus_object_test ()) + die ("object"); + + check_memleaks (); printf ("%s: running marshalling tests\n", "dbus-test"); if (!_dbus_marshal_test ()) diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index c9555e2d..8537be40 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -53,6 +53,7 @@ dbus_bool_t _dbus_sysdeps_test (void); dbus_bool_t _dbus_spawn_test (const char *test_data_dir); dbus_bool_t _dbus_userdb_test (const char *test_data_dir); dbus_bool_t _dbus_memory_test (void); +dbus_bool_t _dbus_object_test (void); dbus_bool_t _dbus_object_id_test (void); dbus_bool_t _dbus_object_registry_test (void); diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index b604a397..81c3fbfe 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -227,6 +227,7 @@ init_global_locks (void) LOCK_ADDR (message_slots), LOCK_ADDR (atomic), LOCK_ADDR (message_handler), + LOCK_ADDR (callback_object), LOCK_ADDR (bus), LOCK_ADDR (shutdown_funcs), LOCK_ADDR (system_users) -- cgit From f1ee877d76000920e6dbec1b59be1ffab39d2c81 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 12 Jul 2003 19:32:35 +0000 Subject: 2003-07-12 Havoc Pennington * dbus/dbus-object-registry.c: implement unit test, fix bugs discovered in process * dbus/dbus-connection.c: remove handler_table and register_handler(), add DBusObjectRegistry usage * dbus/dbus-objectid.c (dbus_object_id_is_null) (dbus_object_id_set_null): new functions --- dbus/dbus-connection.c | 262 +++++----------------- dbus/dbus-connection.h | 16 -- dbus/dbus-object-registry.c | 523 +++++++++++++++++++++++++++++++++++++++++--- dbus/dbus-object-registry.h | 21 +- dbus/dbus-object.h | 6 + dbus/dbus-objectid.c | 28 +++ dbus/dbus-objectid.h | 2 + 7 files changed, 589 insertions(+), 269 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ed29edc9..104fd41f 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -35,6 +35,7 @@ #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-dataslot.h" +#include "dbus-object-registry.h" #if 0 #define CONNECTION_LOCK(connection) do { \ @@ -77,7 +78,7 @@ * you to set a function to be used to monitor the dispatch status. * * If you're using GLib or Qt add-on libraries for D-BUS, there are - * special convenience functions in those libraries that hide + * special convenience APIs in those libraries that hide * all the details of dispatch and watch/timeout monitoring. * For example, dbus_connection_setup_with_g_main(). * @@ -157,7 +158,6 @@ struct DBusConnection DBusWatchList *watches; /**< Stores active watches. */ DBusTimeoutList *timeouts; /**< Stores active timeouts. */ - DBusHashTable *handler_table; /**< Table of registered DBusMessageHandler */ DBusList *filter_list; /**< List of filters. */ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ @@ -180,6 +180,7 @@ struct DBusConnection DBusList *link_cache; /**< A cache of linked list links to prevent contention * for the global linked list mempool lock */ + DBusObjectRegistry *objects; /**< Objects registered with this connection */ }; typedef struct @@ -664,7 +665,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) DBusConnection *connection; DBusWatchList *watch_list; DBusTimeoutList *timeout_list; - DBusHashTable *handler_table, *pending_replies; + DBusHashTable *pending_replies; DBusMutex *mutex; DBusCondVar *message_returned_cond; DBusCondVar *dispatch_cond; @@ -672,10 +673,10 @@ _dbus_connection_new_for_transport (DBusTransport *transport) DBusList *disconnect_link; DBusMessage *disconnect_message; DBusCounter *outgoing_counter; + DBusObjectRegistry *objects; watch_list = NULL; connection = NULL; - handler_table = NULL; pending_replies = NULL; timeout_list = NULL; mutex = NULL; @@ -685,6 +686,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) disconnect_link = NULL; disconnect_message = NULL; outgoing_counter = NULL; + objects = NULL; watch_list = _dbus_watch_list_new (); if (watch_list == NULL) @@ -692,13 +694,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) timeout_list = _dbus_timeout_list_new (); if (timeout_list == NULL) - goto error; - - handler_table = - _dbus_hash_table_new (DBUS_HASH_STRING, - dbus_free, NULL); - if (handler_table == NULL) - goto error; + goto error; pending_replies = _dbus_hash_table_new (DBUS_HASH_INT, @@ -737,6 +733,10 @@ _dbus_connection_new_for_transport (DBusTransport *transport) outgoing_counter = _dbus_counter_new (); if (outgoing_counter == NULL) goto error; + + objects = _dbus_object_registry_new (connection); + if (objects == NULL) + goto error; if (_dbus_modify_sigpipe) _dbus_disable_sigpipe (); @@ -749,7 +749,6 @@ _dbus_connection_new_for_transport (DBusTransport *transport) connection->transport = transport; connection->watches = watch_list; connection->timeouts = timeout_list; - connection->handler_table = handler_table; connection->pending_replies = pending_replies; connection->outgoing_counter = outgoing_counter; connection->filter_list = NULL; @@ -790,9 +789,6 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (connection != NULL) dbus_free (connection); - if (handler_table) - _dbus_hash_table_unref (handler_table); - if (pending_replies) _dbus_hash_table_unref (pending_replies); @@ -804,6 +800,9 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (outgoing_counter) _dbus_counter_unref (outgoing_counter); + + if (objects) + _dbus_object_registry_unref (objects); return NULL; } @@ -853,19 +852,9 @@ void _dbus_connection_handler_destroyed_locked (DBusConnection *connection, DBusMessageHandler *handler) { - DBusHashIter iter; DBusList *link; CONNECTION_LOCK (connection); - - _dbus_hash_iter_init (connection->handler_table, &iter); - while (_dbus_hash_iter_next (&iter)) - { - DBusMessageHandler *h = _dbus_hash_iter_get_value (&iter); - - if (h == handler) - _dbus_hash_iter_remove_entry (&iter); - } link = _dbus_list_get_first_link (&connection->filter_list); while (link != NULL) @@ -1035,7 +1024,6 @@ free_outgoing_message (void *element, static void _dbus_connection_last_unref (DBusConnection *connection) { - DBusHashIter iter; DBusList *link; _dbus_verbose ("Finalizing connection %p\n", connection); @@ -1048,6 +1036,8 @@ _dbus_connection_last_unref (DBusConnection *connection) _dbus_assert (!_dbus_transport_get_is_connected (connection->transport)); /* ---- We're going to call various application callbacks here, hope it doesn't break anything... */ + _dbus_object_registry_free_all_unlocked (connection->objects); + dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); dbus_connection_set_wakeup_main_function (connection, NULL, NULL, NULL); dbus_connection_set_unix_user_function (connection, NULL, NULL, NULL); @@ -1061,14 +1051,6 @@ _dbus_connection_last_unref (DBusConnection *connection) _dbus_data_slot_list_free (&connection->slot_list); /* ---- Done with stuff that invokes application callbacks */ - _dbus_hash_iter_init (connection->handler_table, &iter); - while (_dbus_hash_iter_next (&iter)) - { - DBusMessageHandler *h = _dbus_hash_iter_get_value (&iter); - - _dbus_message_handler_remove_connection (h, connection); - } - link = _dbus_list_get_first_link (&connection->filter_list); while (link != NULL) { @@ -1080,8 +1062,7 @@ _dbus_connection_last_unref (DBusConnection *connection) link = next; } - _dbus_hash_table_unref (connection->handler_table); - connection->handler_table = NULL; + _dbus_object_registry_unref (connection->objects); _dbus_hash_table_unref (connection->pending_replies); connection->pending_replies = NULL; @@ -2237,12 +2218,10 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) DBusDispatchStatus dbus_connection_dispatch (DBusConnection *connection) { - DBusMessageHandler *handler; DBusMessage *message; DBusList *link, *filter_list_copy, *message_link; DBusHandlerResult result; ReplyHandlerData *reply_handler_data; - const char *name; dbus_int32_t reply_serial; DBusDispatchStatus status; @@ -2373,30 +2352,19 @@ dbus_connection_dispatch (DBusConnection *connection) CONNECTION_LOCK (connection); goto out; } - - name = dbus_message_get_name (message); - if (name != NULL) - { - handler = _dbus_hash_table_lookup_string (connection->handler_table, - name); - if (handler != NULL) - { - /* We're still protected from dispatch() reentrancy here - * since we acquired the dispatcher - */ - CONNECTION_UNLOCK (connection); - - _dbus_verbose (" running app handler on message %p (%s)\n", - message, dbus_message_get_name (message)); - - result = _dbus_message_handler_handle_message (handler, connection, - message); - CONNECTION_LOCK (connection); - if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) - goto out; - } - } + /* We're still protected from dispatch() reentrancy here + * since we acquired the dispatcher + */ + _dbus_verbose (" running object handler on message %p (%s)\n", + message, dbus_message_get_name (message)); + + result = _dbus_object_registry_handle_and_unlock (connection->objects, + message); + CONNECTION_LOCK (connection); + if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + goto out; + _dbus_verbose (" done dispatching %p (%s) on connection %p\n", message, dbus_message_get_name (message), connection); @@ -2721,8 +2689,8 @@ dbus_connection_set_unix_user_function (DBusConnection *connection, /** * Adds a message filter. Filters are handlers that are run on - * all incoming messages, prior to the normal handlers - * registered with dbus_connection_register_handler(). + * all incoming messages, prior to the objects + * registered with dbus_connection_register_object(). * Filters are run in the order that they were added. * The same handler can be added as a filter more than once, in * which case it will be run more than once. @@ -2795,153 +2763,6 @@ dbus_connection_remove_filter (DBusConnection *connection, CONNECTION_UNLOCK (connection); } -/** - * Registers a handler for a list of message names. A single handler - * can be registered for any number of message names, but each message - * name can only have one handler at a time. It's not allowed to call - * this function with the name of a message that already has a - * handler. If the function returns #FALSE, the handlers were not - * registered due to lack of memory. - * - * The connection does NOT add a reference to the message handler; - * instead, if the message handler is finalized, the connection simply - * forgets about it. Thus the caller of this function must keep a - * reference to the message handler. - * - * @todo the messages_to_handle arg may be more convenient if it's a - * single string instead of an array. Though right now MessageHandler - * is sort of designed to say be associated with an entire object with - * multiple methods, that's why for example the connection only - * weakrefs it. So maybe the "manual" API should be different. - * - * @param connection the connection - * @param handler the handler - * @param messages_to_handle the messages to handle - * @param n_messages the number of message names in messages_to_handle - * @returns #TRUE on success, #FALSE if no memory or another handler already exists - * - **/ -dbus_bool_t -dbus_connection_register_handler (DBusConnection *connection, - DBusMessageHandler *handler, - const char **messages_to_handle, - int n_messages) -{ - int i; - - _dbus_return_val_if_fail (connection != NULL, FALSE); - _dbus_return_val_if_fail (handler != NULL, FALSE); - _dbus_return_val_if_fail (n_messages >= 0, FALSE); - _dbus_return_val_if_fail (n_messages == 0 || messages_to_handle != NULL, FALSE); - - CONNECTION_LOCK (connection); - i = 0; - while (i < n_messages) - { - DBusHashIter iter; - char *key; - - key = _dbus_strdup (messages_to_handle[i]); - if (key == NULL) - goto failed; - - if (!_dbus_hash_iter_lookup (connection->handler_table, - key, TRUE, - &iter)) - { - dbus_free (key); - goto failed; - } - - if (_dbus_hash_iter_get_value (&iter) != NULL) - { - _dbus_warn ("Bug in application: attempted to register a second handler for %s\n", - messages_to_handle[i]); - dbus_free (key); /* won't have replaced the old key with the new one */ - goto failed; - } - - if (!_dbus_message_handler_add_connection (handler, connection)) - { - _dbus_hash_iter_remove_entry (&iter); - /* key has freed on nuking the entry */ - goto failed; - } - - _dbus_hash_iter_set_value (&iter, handler); - - ++i; - } - - CONNECTION_UNLOCK (connection); - return TRUE; - - failed: - /* unregister everything registered so far, - * so we don't fail partially - */ - dbus_connection_unregister_handler (connection, - handler, - messages_to_handle, - i); - - CONNECTION_UNLOCK (connection); - return FALSE; -} - -/** - * Unregisters a handler for a list of message names. The handlers - * must have been previously registered. - * - * @param connection the connection - * @param handler the handler - * @param messages_to_handle the messages to handle - * @param n_messages the number of message names in messages_to_handle - * - **/ -void -dbus_connection_unregister_handler (DBusConnection *connection, - DBusMessageHandler *handler, - const char **messages_to_handle, - int n_messages) -{ - int i; - - _dbus_return_if_fail (connection != NULL); - _dbus_return_if_fail (handler != NULL); - _dbus_return_if_fail (n_messages >= 0); - _dbus_return_if_fail (n_messages == 0 || messages_to_handle != NULL); - - CONNECTION_LOCK (connection); - i = 0; - while (i < n_messages) - { - DBusHashIter iter; - - if (!_dbus_hash_iter_lookup (connection->handler_table, - (char*) messages_to_handle[i], FALSE, - &iter)) - { - _dbus_warn ("Bug in application: attempted to unregister handler for %s which was not registered\n", - messages_to_handle[i]); - } - else if (_dbus_hash_iter_get_value (&iter) != handler) - { - _dbus_warn ("Bug in application: attempted to unregister handler for %s which was registered by a different handler\n", - messages_to_handle[i]); - } - else - { - _dbus_hash_iter_remove_entry (&iter); - _dbus_message_handler_remove_connection (handler, connection); - } - - ++i; - } - - CONNECTION_UNLOCK (connection); -} - /** * Registers an object with the connection. This object is assigned an * object ID, and will be visible under this ID and with the provided @@ -2951,7 +2772,11 @@ dbus_connection_unregister_handler (DBusConnection *connection, * * As a side effect of calling this function, the "registered" * callback in the #DBusObjectVTable will be invoked. - * + * + * If the object is deleted, be sure to unregister it with + * dbus_connection_unregister_object() or it will continue to get + * messages. + * * @param connection the connection to register the instance with * @param interfaces #NULL-terminated array of interface names the instance supports * @param vtable virtual table of functions for manipulating the instance @@ -2966,8 +2791,15 @@ dbus_connection_register_object (DBusConnection *connection, void *object_impl, DBusObjectID *object_id) { + _dbus_return_val_if_fail (connection != NULL, FALSE); + + CONNECTION_LOCK (connection); - return FALSE; + return _dbus_object_registry_add_and_unlock (connection->objects, + interfaces, + vtable, + object_impl, + object_id); } /** @@ -2983,8 +2815,12 @@ void dbus_connection_unregister_object (DBusConnection *connection, const DBusObjectID *object_id) { - + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + return _dbus_object_registry_remove_and_unlock (connection->objects, + object_id); } static DBusDataSlotAllocator slot_allocator; diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 6c0da920..7bf1221a 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -36,15 +36,8 @@ DBUS_BEGIN_DECLS; typedef struct DBusWatch DBusWatch; typedef struct DBusTimeout DBusTimeout; typedef struct DBusMessageHandler DBusMessageHandler; -typedef struct DBusObject DBusObject; typedef struct DBusPreallocatedSend DBusPreallocatedSend; -typedef enum -{ - DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */ - DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS /**< Run any additional handlers that are interested in this message. */ -} DBusHandlerResult; - typedef enum { DBUS_WATCH_READABLE = 1 << 0, /**< As in POLLIN */ @@ -162,15 +155,6 @@ dbus_bool_t dbus_connection_add_filter (DBusConnection *connection, void dbus_connection_remove_filter (DBusConnection *connection, DBusMessageHandler *handler); -dbus_bool_t dbus_connection_register_handler (DBusConnection *connection, - DBusMessageHandler *handler, - const char **messages_to_handle, - int n_messages); -void dbus_connection_unregister_handler (DBusConnection *connection, - DBusMessageHandler *handler, - const char **messages_to_handle, - int n_messages); - /* Objects */ dbus_bool_t dbus_connection_register_object (DBusConnection *connection, const char **interfaces, diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index eba2d8fb..64320179 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -23,6 +23,7 @@ #include "dbus-object-registry.h" #include "dbus-connection-internal.h" #include "dbus-internals.h" +#include "dbus-hash.h" #include /** @@ -30,16 +31,27 @@ * @ingroup DBusInternals * @brief DBusObjectRegistry is used by DBusConnection to track object IDs * - * Types and functions related to DBusObjectRegistry + * Types and functions related to DBusObjectRegistry. These + * are all internal. * * @{ */ typedef struct DBusObjectEntry DBusObjectEntry; +typedef struct DBusInterfaceEntry DBusInterfaceEntry; + +#define DBUS_MAX_OBJECTS_PER_INTERFACE 65535 +struct DBusInterfaceEntry +{ + unsigned int n_objects : 16; /**< Number of objects with this interface */ + unsigned int n_allocated : 16; /**< Allocated size of objects array */ + dbus_uint16_t *objects; /**< Index of each object with the interface */ + char name[4]; /**< Name of interface (actually allocated larger) */ +}; /* 14 bits for object index, 32K objects */ #define DBUS_OBJECT_INDEX_BITS (14) -#define DBUS_OBJECT_INDEX_MASK (0x7fff) +#define DBUS_OBJECT_INDEX_MASK (0x3fff) #define DBUS_MAX_OBJECTS_PER_CONNECTION DBUS_OBJECT_INDEX_MASK struct DBusObjectEntry { @@ -48,6 +60,7 @@ struct DBusObjectEntry void *object_impl; /**< Pointer to application-supplied implementation */ const DBusObjectVTable *vtable; /**< Virtual table for this object */ + DBusInterfaceEntry **interfaces; /**< NULL-terminated list of interfaces */ }; struct DBusObjectRegistry @@ -58,21 +71,58 @@ struct DBusObjectRegistry DBusObjectEntry *entries; int n_entries_allocated; int n_entries_used; + + DBusHashTable *interface_table; }; +static void +free_interface_entry (void *entry) +{ + DBusInterfaceEntry *iface = entry; + + if (iface == NULL) /* DBusHashTable stupidity */ + return; + + dbus_free (iface->objects); + dbus_free (iface); +} + DBusObjectRegistry* _dbus_object_registry_new (DBusConnection *connection) { DBusObjectRegistry *registry; + DBusHashTable *interface_table; + + /* the connection passed in here isn't fully constructed, + * so don't do anything more than store a pointer to + * it + */ + registry = NULL; + interface_table = NULL; + registry = dbus_new0 (DBusObjectRegistry, 1); if (registry == NULL) - return NULL; + goto oom; + + interface_table = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, free_interface_entry); + if (interface_table == NULL) + goto oom; registry->refcount = 1; registry->connection = connection; - + registry->interface_table = interface_table; + return registry; + + oom: + if (registry) + dbus_free (registry); + if (interface_table) + _dbus_hash_table_unref (interface_table); + + return NULL; } void @@ -92,8 +142,20 @@ _dbus_object_registry_unref (DBusObjectRegistry *registry) if (registry->refcount == 0) { + int i; + _dbus_assert (registry->n_entries_used == 0); + _dbus_assert (_dbus_hash_table_get_n_entries (registry->interface_table) == 0); + i = 0; + while (i < registry->n_entries_allocated) + { + if (registry->entries[i].interfaces) + dbus_free (registry->entries[i].interfaces); + ++i; + } + + _dbus_hash_table_unref (registry->interface_table); dbus_free (registry->entries); dbus_free (registry); } @@ -104,7 +166,7 @@ _dbus_object_registry_unref (DBusObjectRegistry *registry) (((dbus_uint32_t)(entry)->id_times_used) << DBUS_OBJECT_INDEX_BITS)) #define ID_TO_INDEX(id) \ - (((dbus_uint32_t) (id)) | DBUS_OBJECT_INDEX_MASK) + (((dbus_uint32_t) (id)) & DBUS_OBJECT_INDEX_MASK) #define ID_TO_TIMES_USED(id) \ (((dbus_uint32_t) (id)) >> DBUS_OBJECT_INDEX_BITS) @@ -121,7 +183,7 @@ validate_id (DBusObjectRegistry *registry, idx = ID_TO_INDEX (low_bits); times_used = ID_TO_TIMES_USED (low_bits); - + if (idx >= registry->n_entries_allocated) return NULL; if (registry->entries[idx].vtable == NULL) @@ -141,12 +203,154 @@ info_from_entry (DBusObjectRegistry *registry, { info->connection = registry->connection; info->object_impl = entry->object_impl; - dbus_object_id_set_high_bits (&info->object_id, - _dbus_connection_get_id (registry->connection)); +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + dbus_object_id_set_high_bits (&info->object_id, + _dbus_connection_get_id (registry->connection)); +#ifdef DBUS_BUILD_TESTS + else + dbus_object_id_set_high_bits (&info->object_id, 1); +#endif + dbus_object_id_set_low_bits (&info->object_id, ENTRY_TO_ID (entry)); } +static DBusInterfaceEntry* +lookup_interface (DBusObjectRegistry *registry, + const char *name, + dbus_bool_t create_if_not_found) +{ + DBusInterfaceEntry *entry; + int sz; + int len; + + entry = _dbus_hash_table_lookup_string (registry->interface_table, + name); + if (entry != NULL || !create_if_not_found) + return entry; + + _dbus_assert (create_if_not_found); + + len = strlen (name); + sz = _DBUS_STRUCT_OFFSET (DBusInterfaceEntry, name) + len + 1; + entry = dbus_malloc (sz); + if (entry == NULL) + return NULL; + entry->n_objects = 0; + entry->n_allocated = 0; + entry->objects = NULL; + memcpy (entry->name, name, len + 1); + + if (!_dbus_hash_table_insert_string (registry->interface_table, + entry->name, entry)) + { + dbus_free (entry); + return NULL; + } + + return entry; +} + +static void +delete_interface (DBusObjectRegistry *registry, + DBusInterfaceEntry *entry) +{ + _dbus_hash_table_remove_string (registry->interface_table, + entry->name); +} + +static dbus_bool_t +interface_entry_add_object (DBusInterfaceEntry *entry, + dbus_uint16_t object_index) +{ + if (entry->n_objects == entry->n_allocated) + { + unsigned int new_alloc; + dbus_uint16_t *new_objects; + + if (entry->n_allocated == 0) + new_alloc = 2; + else + new_alloc = entry->n_allocated * 2; + + /* Right now MAX_OBJECTS_PER_INTERFACE can't possibly be reached + * since the max number of objects _total_ is smaller, but the + * code is here for future robustness. + */ + + if (new_alloc > DBUS_MAX_OBJECTS_PER_INTERFACE) + new_alloc = DBUS_MAX_OBJECTS_PER_INTERFACE; + if (new_alloc == entry->n_allocated) + { + _dbus_warn ("Attempting to register another instance with interface %s, but max count %d reached\n", + entry->name, DBUS_MAX_OBJECTS_PER_INTERFACE); + return FALSE; + } + + new_objects = dbus_realloc (entry->objects, new_alloc * sizeof (dbus_uint16_t)); + if (new_objects == NULL) + return FALSE; + entry->objects = new_objects; + entry->n_allocated = new_alloc; + } + + _dbus_assert (entry->n_objects < entry->n_allocated); + + entry->objects[entry->n_objects] = object_index; + entry->n_objects += 1; + + return TRUE; +} + +static void +interface_entry_remove_object (DBusInterfaceEntry *entry, + dbus_uint16_t object_index) +{ + unsigned int i; + + i = 0; + while (i < entry->n_objects) + { + if (entry->objects[i] == object_index) + break; + ++i; + } + + if (i == entry->n_objects) + { + _dbus_assert_not_reached ("Tried to remove object from an interface that didn't list that object\n"); + return; + } + + memmove (&entry->objects[i], + &entry->objects[i+1], + (entry->n_objects - i - 1) * sizeof (entry->objects[0])); + entry->n_objects -= 1; +} + +static void +object_remove_from_interfaces (DBusObjectRegistry *registry, + DBusObjectEntry *entry) +{ + if (entry->interfaces != NULL) + { + int i; + + i = 0; + while (entry->interfaces[i] != NULL) + { + DBusInterfaceEntry *iface = entry->interfaces[i]; + + interface_entry_remove_object (iface, entry->id_index); + if (iface->n_objects == 0) + delete_interface (registry, iface); + ++i; + } + } +} + dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, const char **interfaces, @@ -154,9 +358,10 @@ _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, void *object_impl, DBusObjectID *object_id) { + int idx; int i; DBusObjectInfo info; - + if (registry->n_entries_used == registry->n_entries_allocated) { DBusObjectEntry *new_entries; @@ -170,7 +375,7 @@ _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, { _dbus_warn ("Attempting to register a new D-BUS object, but maximum object count of %d reached\n", DBUS_MAX_OBJECTS_PER_CONNECTION); - return FALSE; + goto out_0; } new_alloc = registry->n_entries_allocated * 2; @@ -182,7 +387,7 @@ _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, new_alloc * sizeof (DBusObjectEntry)); if (new_entries == NULL) - return FALSE; + goto out_0; memset (&new_entries[registry->n_entries_allocated], '\0', @@ -199,7 +404,7 @@ _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, */ if (registry->entries[registry->n_entries_used].vtable == NULL) { - i = registry->n_entries_used; + idx = registry->n_entries_used; } else { @@ -213,34 +418,125 @@ _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, * the range [0, n_entries_used). Thus, there is * at least one blank entry inside that range. */ - i = 0; - while (i < registry->n_entries_used) + idx = 0; + while (idx < registry->n_entries_used) { - if (registry->entries[i].vtable == NULL) + if (registry->entries[idx].vtable == NULL) break; - ++i; + ++idx; } - _dbus_assert (i < registry->n_entries_used); + _dbus_assert (idx < registry->n_entries_used); } + + registry->entries[idx].id_index = idx; + /* Overflow is OK here, but zero isn't as it's a null ID */ + registry->entries[idx].id_times_used += 1; + if (registry->entries[idx].id_times_used == 0) + registry->entries[idx].id_times_used += 1; + + registry->entries[idx].vtable = vtable; + registry->entries[idx].object_impl = object_impl; - registry->entries[i].id_index = i; - /* Overflow is OK here */ - registry->entries[i].id_times_used += 1; + registry->n_entries_used += 1; - registry->entries[i].vtable = vtable; - registry->entries[i].object_impl = object_impl; + i = 0; + if (interfaces != NULL) + { + while (interfaces[i] != NULL) + ++i; + } + + if (i > 0) + { + DBusInterfaceEntry **new_interfaces; + + new_interfaces = + dbus_realloc (registry->entries[idx].interfaces, + (i + 1) * sizeof (DBusInterfaceEntry*)); + + if (new_interfaces == NULL) + { + /* maintain invariant that .interfaces array points to something + * valid in oom handler (entering this function it pointed to + * stale data but a valid malloc block) + */ + dbus_free (registry->entries[idx].interfaces); + registry->entries[idx].interfaces = NULL; + goto out_1; + } - info_from_entry (registry, &info, ®istry->entries[i]); + /* NULL-init so it's NULL-terminated and the OOM + * case can see how far we got + */ + while (i >= 0) + { + new_interfaces[i] = NULL; + --i; + } + + registry->entries[idx].interfaces = new_interfaces; + } + else + { + dbus_free (registry->entries[idx].interfaces); + registry->entries[idx].interfaces = NULL; + } + + /* Fill in interfaces */ + if (interfaces != NULL) + { + i = 0; + while (interfaces[i] != NULL) + { + DBusInterfaceEntry *iface; + + iface = lookup_interface (registry, interfaces[i], + TRUE); + if (iface == NULL) + goto out_1; + + if (!interface_entry_add_object (iface, idx)) + { + if (iface->n_objects == 0) + delete_interface (registry, iface); + goto out_1; + } + + registry->entries[idx].interfaces[i] = iface; + + ++i; + } + } + + info_from_entry (registry, &info, ®istry->entries[idx]); if (object_id) *object_id = info.object_id; /* Drop lock and invoke application code */ - _dbus_connection_unlock (registry->connection); - +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + (* vtable->registered) (&info); return TRUE; + + out_1: + registry->entries[idx].vtable = NULL; + registry->entries[idx].object_impl = NULL; + registry->n_entries_used -= 1; + + object_remove_from_interfaces (registry, + ®istry->entries[idx]); + + out_0: +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + return FALSE; } void @@ -255,33 +551,44 @@ _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, if (entry == NULL) { _dbus_warn ("Tried to unregister a nonexistent D-BUS object ID\n"); +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + return; } + object_remove_from_interfaces (registry, entry); + info_from_entry (registry, &info, entry); vtable = entry->vtable; entry->vtable = NULL; entry->object_impl = NULL; registry->n_entries_used -= 1; - + /* Drop lock and invoke application code */ - _dbus_connection_unlock (registry->connection); +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); (* vtable->unregistered) (&info); } -void +DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, DBusMessage *message) { /* FIXME */ + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) { int i; - + i = 0; while (registry->n_entries_used > 0) { @@ -291,6 +598,9 @@ _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) DBusObjectInfo info; const DBusObjectVTable *vtable; + object_remove_from_interfaces (registry, + ®istry->entries[i]); + info_from_entry (registry, &info, ®istry->entries[i]); vtable = registry->entries[i].vtable; registry->entries[i].vtable = NULL; @@ -313,6 +623,157 @@ _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) #include "dbus-test.h" #include +static void +noop_message_function (DBusObjectInfo *info, + DBusMessage *message) +{ + /* nothing */ +} + +static void +add_and_remove_objects (DBusObjectRegistry *registry) +{ +#define N_OBJECTS 73 + DBusObjectID ids[N_OBJECTS]; + const char *zero_interfaces[] = { NULL }; + const char *one_interface[] = { "org.freedesktop.Test.Blah", NULL }; + const char *three_interfaces[] = { "org.freedesktop.Test.Blah", + "org.freedesktop.Test.Baz", + "org.freedesktop.Test.Foo", + NULL }; + int i; + + i = 0; + while (i < N_OBJECTS) + { + DBusCallbackObject *callback; + const char **interfaces; + + callback = dbus_callback_object_new (noop_message_function, NULL, NULL); + if (callback == NULL) + goto out; + + switch (i % 3) + { + case 0: + interfaces = zero_interfaces; + break; + case 1: + interfaces = one_interface; + break; + case 2: + interfaces = three_interfaces; + break; + } + + if (!_dbus_object_registry_add_and_unlock (registry, + interfaces, + dbus_callback_object_vtable, + callback, + &ids[i])) + { + dbus_callback_object_unref (callback); + goto out; + } + + dbus_callback_object_unref (callback); + + ++i; + } + + i = 0; + while (i < N_OBJECTS) + { + if (i > (N_OBJECTS - 20) || (i % 3) == 0) + { + _dbus_object_registry_remove_and_unlock (registry, + &ids[i]); + dbus_object_id_set_null (&ids[i]); + } + + ++i; + } + + i = 0; + while (i < N_OBJECTS) + { + if (dbus_object_id_is_null (&ids[i])) + { + DBusCallbackObject *callback; + const char **interfaces; + + callback = dbus_callback_object_new (noop_message_function, NULL, NULL); + if (callback == NULL) + goto out; + + switch (i % 4) + { + case 0: + interfaces = NULL; + break; + case 1: + interfaces = zero_interfaces; + break; + case 2: + interfaces = one_interface; + break; + case 3: + interfaces = three_interfaces; + break; + } + + if (!_dbus_object_registry_add_and_unlock (registry, + interfaces, + dbus_callback_object_vtable, + callback, + &ids[i])) + { + dbus_callback_object_unref (callback); + goto out; + } + + dbus_callback_object_unref (callback); + } + + ++i; + } + + i = 0; + while (i < (N_OBJECTS - 30)) + { + _dbus_assert (!dbus_object_id_is_null (&ids[i])); + + _dbus_object_registry_remove_and_unlock (registry, + &ids[i]); + ++i; + } + + out: + /* unregister the rest this way, to test this function */ + _dbus_object_registry_free_all_unlocked (registry); +} + +static dbus_bool_t +object_registry_test_iteration (void *data) +{ + DBusObjectRegistry *registry; + + registry = _dbus_object_registry_new (NULL); + if (registry == NULL) + return TRUE; + + /* we do this twice since realloc behavior will differ each time, + * and the IDs will get recycled leading to slightly different + * codepaths + */ + add_and_remove_objects (registry); + add_and_remove_objects (registry); + + _dbus_object_registry_unref (registry); + + return TRUE; +} + /** * @ingroup DBusObjectRegistry * Unit test for DBusObjectRegistry @@ -321,7 +782,9 @@ _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) dbus_bool_t _dbus_object_registry_test (void) { - /* FIXME */ + _dbus_test_oom_handling ("object registry", + object_registry_test_iteration, + NULL); return TRUE; } diff --git a/dbus/dbus-object-registry.h b/dbus/dbus-object-registry.h index d33664e5..57009c87 100644 --- a/dbus/dbus-object-registry.h +++ b/dbus/dbus-object-registry.h @@ -33,16 +33,17 @@ DBusObjectRegistry* _dbus_object_registry_new (DBusConnection *connection) void _dbus_object_registry_ref (DBusObjectRegistry *registry); void _dbus_object_registry_unref (DBusObjectRegistry *registry); -dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, - const char **interfaces, - const DBusObjectVTable *vtable, - void *object_impl, - DBusObjectID *object_id); -void _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, - const DBusObjectID *object_id); -void _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, - DBusMessage *message); -void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry); +dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id); +void _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, + const DBusObjectID *object_id); +DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message); +void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry); + DBUS_END_DECLS; diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h index b05d9c4b..84fb2ede 100644 --- a/dbus/dbus-object.h +++ b/dbus/dbus-object.h @@ -39,6 +39,12 @@ typedef struct DBusObjectVTable DBusObjectVTable; typedef struct DBusObjectInfo DBusObjectInfo; typedef struct DBusCallbackObject DBusCallbackObject; +typedef enum +{ + DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */ + DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS /**< Run any additional handlers that are interested in this message. */ +} DBusHandlerResult; + struct DBusObjectInfo { void *object_impl; /**< Object information */ diff --git a/dbus/dbus-objectid.c b/dbus/dbus-objectid.c index 1fb83e44..55ae0d48 100644 --- a/dbus/dbus-objectid.c +++ b/dbus/dbus-objectid.c @@ -177,6 +177,34 @@ dbus_object_id_set_low_bits (DBusObjectID *obj_id, #endif } +/** + * Set the object ID to an invalid value that cannot + * correspond to a valid object. + * + * @param obj_id the object ID + */ +void +dbus_object_id_set_null (DBusObjectID *obj_id) +{ + memset (obj_id, '\0', sizeof (DBusObjectID)); +} + +/** + * Check whether the object ID is set to a null value + * + * @param obj_id the object ID + * @returns #TRUE if null + */ +dbus_bool_t +dbus_object_id_is_null (const DBusObjectID *obj_id) +{ +#ifdef DBUS_HAVE_INT64 + return VALUE (obj_id) == 0; +#else + return HIGH_BITS (obj_id) == 0 && LOW_BITS (obj_id) == 0; +#endif +} + #ifdef DBUS_HAVE_INT64 /** * An object ID contains 64 bits of data. This function diff --git a/dbus/dbus-objectid.h b/dbus/dbus-objectid.h index b5e1f606..ad8ea1c5 100644 --- a/dbus/dbus-objectid.h +++ b/dbus/dbus-objectid.h @@ -54,6 +54,8 @@ void dbus_object_id_set_high_bits (DBusObjectID *obj_id dbus_uint32_t value); void dbus_object_id_set_low_bits (DBusObjectID *obj_id, dbus_uint32_t value); +void dbus_object_id_set_null (DBusObjectID *obj_id); +dbus_bool_t dbus_object_id_is_null (const DBusObjectID *obj_id); #ifdef DBUS_HAVE_INT64 dbus_uint64_t dbus_object_id_get_as_integer (const DBusObjectID *obj_id); void dbus_object_id_set_as_integer (DBusObjectID *obj_id, -- cgit From 8b7fe6f99dd35f32443a4e23466c8a1e4cfaa32b Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 17 Jul 2003 01:10:57 +0000 Subject: 2003-07-13 Havoc Pennington * dbus/dbus-object.h (struct DBusObjectVTable): add padding fields to DBusObjectVTable and DBusObjectInfo --- dbus/dbus-connection.c | 8 ++++++-- dbus/dbus-object.c | 3 ++- dbus/dbus-object.h | 11 ++++++++--- 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 104fd41f..d604bfcb 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2791,8 +2791,12 @@ dbus_connection_register_object (DBusConnection *connection, void *object_impl, DBusObjectID *object_id) { - _dbus_return_val_if_fail (connection != NULL, FALSE); - + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (vtable != NULL, FALSE); + _dbus_return_val_if_fail (vtable->dbus_internal_pad1 == NULL); + _dbus_return_val_if_fail (vtable->dbus_internal_pad2 == NULL); + _dbus_return_val_if_fail (vtable->dbus_internal_pad3 == NULL); + CONNECTION_LOCK (connection); return _dbus_object_registry_add_and_unlock (connection->objects, diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c index 262f75ca..c3f1536d 100644 --- a/dbus/dbus-object.c +++ b/dbus/dbus-object.c @@ -136,7 +136,8 @@ callback_object_message (DBusObjectInfo *info, static const DBusObjectVTable callback_object_vtable = { callback_object_registered, callback_object_unregistered, - callback_object_message + callback_object_message, + NULL, NULL, NULL }; /** diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h index 84fb2ede..a0a53eb0 100644 --- a/dbus/dbus-object.h +++ b/dbus/dbus-object.h @@ -47,9 +47,11 @@ typedef enum struct DBusObjectInfo { - void *object_impl; /**< Object information */ - DBusObjectID object_id; - DBusConnection *connection; + void *object_impl; /**< Object implementation pointer provided by app */ + DBusObjectID object_id; /**< Object ID */ + DBusConnection *connection; /**< The connection object ID is for */ + void *dbus_internal_pad1; /**< Padding, do not use */ + void *dbus_internal_pad2; /**< Padding, do not use */ }; typedef void (* DBusObjectRegisteredFunction) (DBusObjectInfo *info); @@ -62,6 +64,9 @@ struct DBusObjectVTable DBusObjectRegisteredFunction registered; DBusObjectUnregisteredFunction unregistered; DBusObjectMessageFunction message; + void (* dbus_internal_pad1) (void *); + void (* dbus_internal_pad2) (void *); + void (* dbus_internal_pad3) (void *); }; extern const DBusObjectVTable *dbus_callback_object_vtable; -- cgit From fe195a911d86d0a71349988360de65cfac1b3f86 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 2 Aug 2003 01:59:14 +0000 Subject: 2003-08-01 Havoc Pennington * dbus/dbus-protocol.h (DBUS_MESSAGE_TYPE_*): introduce a message type enum to distinguish kinds of message (DBUS_HEADER_FLAG_NO_REPLY_EXPECTED): flag for a message that need not be replied to 2003-08-01 Havoc Pennington * dbus/dbus-marshal.c: adapt to DBusObjectID changes (unpack_8_octets): fix no-64-bit-int bug * dbus/dbus-object-registry.c (validate_id): validate the connection ID bits, not just the instance ID. * dbus/dbus-connection.c (_dbus_connection_init_id): initialize the connection-global 33 bits of the object ID * dbus/dbus-object-registry.c (info_from_entry): fill in object ID in the new way * dbus/dbus-objectid.h: rather than high/low bits, specifically define server/client/instance bits. --- dbus/dbus-auth.c | 2 - dbus/dbus-connection-internal.h | 3 +- dbus/dbus-connection.c | 19 +-- dbus/dbus-marshal.c | 55 ++------ dbus/dbus-message.c | 2 + dbus/dbus-object-registry.c | 43 ++++-- dbus/dbus-objectid.c | 288 ++++++++++++++++++++++++++++++---------- dbus/dbus-objectid.h | 34 +++-- dbus/dbus-protocol.h | 9 +- dbus/dbus-string.c | 2 +- 10 files changed, 310 insertions(+), 147 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index b496dba0..95910445 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -28,8 +28,6 @@ #include "dbus-sha.h" #include "dbus-userdb.h" -/* See doc/dbus-sasl-profile.txt */ - /** * @defgroup DBusAuth Authentication * @ingroup DBusInternals diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index eaa35955..5bcbcc2f 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -81,7 +81,8 @@ void _dbus_message_handler_remove_connection (DBusMessageHandl DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandler *handler, DBusConnection *connection, DBusMessage *message); -dbus_uint32_t _dbus_connection_get_id (DBusConnection *connection); +void _dbus_connection_init_id (DBusConnection *connection, + DBusObjectID *id); DBUS_END_DECLS; diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index d604bfcb..4b72d600 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -910,19 +910,22 @@ _dbus_connection_handle_watch (DBusWatch *watch, } /** - * Get the ID to be used in the high bits of an object ID for an object + * Get the server ID to be used in the object ID for an object * registered with this connection. * * @todo implement this function * * @param connection the connection. - * @returns the connection portion of the object ID + * @returns the portion of the object ID */ -dbus_uint32_t -_dbus_connection_get_id (DBusConnection *connection) +void +_dbus_connection_init_id (DBusConnection *connection, + DBusObjectID *object_id) { /* FIXME */ - return 1492; + dbus_object_id_set_server_bits (object_id, 15); + dbus_object_id_set_client_bits (object_id, 31); + dbus_object_id_set_is_server_bit (object_id, FALSE); } /** @} */ @@ -2793,9 +2796,9 @@ dbus_connection_register_object (DBusConnection *connection, { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); - _dbus_return_val_if_fail (vtable->dbus_internal_pad1 == NULL); - _dbus_return_val_if_fail (vtable->dbus_internal_pad2 == NULL); - _dbus_return_val_if_fail (vtable->dbus_internal_pad3 == NULL); + _dbus_return_val_if_fail (vtable->dbus_internal_pad1 == NULL, FALSE); + _dbus_return_val_if_fail (vtable->dbus_internal_pad2 == NULL, FALSE); + _dbus_return_val_if_fail (vtable->dbus_internal_pad3 == NULL, FALSE); CONNECTION_LOCK (connection); diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 2399a282..aaf97c7c 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -80,19 +80,7 @@ typedef union dbus_uint64_t u; #endif double d; -#ifdef WORDS_BIGENDIAN - struct - { - dbus_uint32_t high; - dbus_uint32_t low; - } bits; -#else - struct - { - dbus_uint32_t low; - dbus_uint32_t high; - } bits; -#endif + DBusObjectID object_id; } DBusOctets8; static DBusOctets8 @@ -111,7 +99,8 @@ unpack_8_octets (int byte_order, r.u = DBUS_UINT64_FROM_BE (*(dbus_uint64_t*)data); #else r.d = *(double*)data; - swap_bytes (&r, sizeof (r)); + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + swap_bytes ((unsigned char*) &r, sizeof (r)); #endif return r; @@ -453,14 +442,8 @@ _dbus_marshal_set_object_id (DBusString *str, const DBusObjectID *value) { DBusOctets8 r; -#ifdef DBUS_HAVE_INT64 - r.u = dbus_object_id_get_as_integer (value); -#else - r.bits.low = dbus_object_id_get_low_bits (value); - r.bits.high = dbus_object_id_get_high_bits (value); -#endif - _dbus_assert (r.bits.low == dbus_object_id_get_low_bits (value)); - _dbus_assert (r.bits.high == dbus_object_id_get_high_bits (value)); + + r.object_id = *value; set_8_octets (str, byte_order, offset, r); } @@ -724,7 +707,7 @@ marshal_8_octets_array (DBusString *str, #ifdef DBUS_HAVE_INT64 *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d)); #else - swap_bytes (d, 8); + swap_bytes ((unsigned char*) d, 8); #endif d += 8; } @@ -900,14 +883,8 @@ _dbus_marshal_object_id (DBusString *str, const DBusObjectID *value) { DBusOctets8 r; -#ifdef DBUS_HAVE_INT64 - r.u = dbus_object_id_get_as_integer (value); -#else - r.bits.low = dbus_object_id_get_low_bits (value); - r.bits.high = dbus_object_id_get_high_bits (value); -#endif - _dbus_assert (r.bits.low == dbus_object_id_get_low_bits (value)); - _dbus_assert (r.bits.high == dbus_object_id_get_high_bits (value)); + + r.object_id = *value; return marshal_8_octets (str, byte_order, r); } @@ -1242,7 +1219,7 @@ demarshal_8_octets_array (const DBusString *str, #ifdef DBUS_HAVE_INT64 retval[i].u = DBUS_UINT64_SWAP_LE_BE (retval[i].u); #else - swap_bytes (&retval[i], 8); + swap_bytes ((unsigned char *) &retval[i], 8); #endif } } @@ -1481,14 +1458,7 @@ _dbus_demarshal_object_id (const DBusString *str, r = demarshal_8_octets (str, byte_order, pos, new_pos); -#ifdef DBUS_HAVE_INT64 - dbus_object_id_set_as_integer (value, r.u); -#else - dbus_object_id_set_low_bits (value, r.bits.low); - dbus_object_id_set_high_bits (value, r.bits.high); -#endif - _dbus_assert (dbus_object_id_get_low_bits (value) == r.bits.low); - _dbus_assert (dbus_object_id_get_high_bits (value) == r.bits.high); + *value = r.object_id; } /** @@ -2312,8 +2282,9 @@ _dbus_marshal_test (void) #endif /* DBUS_HAVE_INT64 */ /* Marshal object IDs */ - dbus_object_id_set_high_bits (&obj_id, 0xfffe); - dbus_object_id_set_low_bits (&obj_id, 0xaacc); + dbus_object_id_set_server_bits (&obj_id, 0xfffe); + dbus_object_id_set_client_bits (&obj_id, 0xaacc); + dbus_object_id_set_instance_bits (&obj_id, 0x70f00f0f); if (!_dbus_marshal_object_id (&str, DBUS_BIG_ENDIAN, &obj_id)) _dbus_assert_not_reached ("could not marshal object ID value"); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index fab37720..52226603 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -5855,10 +5855,12 @@ _dbus_message_test (const char *test_data_dir) _DBUS_N_ELEMENTS (our_uint32_array), DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, our_int32_array, _DBUS_N_ELEMENTS (our_int32_array), +#ifdef DBUS_HAVE_INT64 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, our_uint64_array, _DBUS_N_ELEMENTS (our_uint64_array), DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, our_int64_array, _DBUS_N_ELEMENTS (our_int64_array), +#endif DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, our_string_array, _DBUS_N_ELEMENTS (our_string_array), DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, our_double_array, diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index 64320179..a550f8e2 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -177,12 +177,27 @@ validate_id (DBusObjectRegistry *registry, { int idx; int times_used; - dbus_uint32_t low_bits; - - low_bits = dbus_object_id_get_low_bits (object_id); + dbus_uint32_t instance_bits; + + instance_bits = dbus_object_id_get_instance_bits (object_id); - idx = ID_TO_INDEX (low_bits); - times_used = ID_TO_TIMES_USED (low_bits); + /* Verify that connection ID bits are the same */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + { + DBusObjectID tmp_id; + + _dbus_connection_init_id (registry->connection, + &tmp_id); + dbus_object_id_set_instance_bits (&tmp_id, instance_bits); + + if (!dbus_object_id_equal (&tmp_id, object_id)) + return NULL; + } + + idx = ID_TO_INDEX (instance_bits); + times_used = ID_TO_TIMES_USED (instance_bits); if (idx >= registry->n_entries_allocated) return NULL; @@ -206,15 +221,23 @@ info_from_entry (DBusObjectRegistry *registry, #ifdef DBUS_BUILD_TESTS if (registry->connection) #endif - dbus_object_id_set_high_bits (&info->object_id, - _dbus_connection_get_id (registry->connection)); + _dbus_connection_init_id (registry->connection, + &info->object_id); #ifdef DBUS_BUILD_TESTS else - dbus_object_id_set_high_bits (&info->object_id, 1); + { + dbus_object_id_set_server_bits (&info->object_id, 1); + dbus_object_id_set_client_bits (&info->object_id, 2); + } #endif + + _dbus_assert (dbus_object_id_get_server_bits (&info->object_id) != 0); + _dbus_assert (dbus_object_id_get_client_bits (&info->object_id) != 0); - dbus_object_id_set_low_bits (&info->object_id, - ENTRY_TO_ID (entry)); + dbus_object_id_set_instance_bits (&info->object_id, + ENTRY_TO_ID (entry)); + + _dbus_assert (dbus_object_id_get_instance_bits (&info->object_id) != 0); } static DBusInterfaceEntry* diff --git a/dbus/dbus-objectid.c b/dbus/dbus-objectid.c index 55ae0d48..f2b27b61 100644 --- a/dbus/dbus-objectid.c +++ b/dbus/dbus-objectid.c @@ -25,12 +25,34 @@ #include "dbus-internals.h" #ifdef DBUS_HAVE_INT64 -#define VALUE(objid) ((objid)->dbus_do_not_use_dummy1) -#define HIGH_BITS(objid) ((dbus_uint32_t) (VALUE (obj_id) >> 32)) -#define LOW_BITS(objid) ((dbus_uint32_t) (VALUE (obj_id) & DBUS_UINT64_CONSTANT (0x00000000ffffffff))) +#define VALUE(objid) ((objid)->dbus_do_not_use_dummy1) +#define SERVER_MASK DBUS_UINT64_CONSTANT (0xffff000000000000) +#define CLIENT_MASK DBUS_UINT64_CONSTANT (0x0000ffff00000000) +#define IS_SERVER_MASK DBUS_UINT64_CONSTANT (0x0000000080000000) +#define INSTANCE_MASK DBUS_UINT64_CONSTANT (0x000000007fffffff) +#define SERVER_BITS(objid) ((dbus_uint16_t) (VALUE (obj_id) >> 48)) +#define CLIENT_BITS(objid) ((dbus_uint16_t) ((VALUE (obj_id) & CLIENT_MASK) >> 32)) +#define IS_SERVER_BIT(objid) ((VALUE (obj_id) & IS_SERVER_MASK) != 0) +#define INSTANCE_BITS(objid) ((dbus_uint32_t) (VALUE (obj_id) & INSTANCE_MASK)) #else -#define HIGH_BITS(objid) ((objid)->dbus_do_not_use_dummy1) -#define LOW_BITS(objid) ((objid)->dbus_do_not_use_dummy2) +/* We care about the exact packing since in dbus-marshal.c we + * just use the DBusObjectID struct as-is. + */ +#ifdef WORDS_BIGENDIAN +#define HIGH_VALUE(objid) ((objid)->dbus_do_not_use_dummy2) +#define LOW_VALUE(objid) ((objid)->dbus_do_not_use_dummy3) +#else +#define HIGH_VALUE(objid) ((objid)->dbus_do_not_use_dummy3) +#define LOW_VALUE(objid) ((objid)->dbus_do_not_use_dummy2) +#endif +#define SERVER_MASK (0xffff0000) +#define CLIENT_MASK (0x0000ffff) +#define IS_SERVER_MASK (0x80000000) +#define INSTANCE_MASK (0x7fffffff) +#define SERVER_BITS(objid) ((HIGH_VALUE (objid) & SERVER_MASK) >> 16) +#define CLIENT_BITS(objid) (HIGH_VALUE (objid) & CLIENT_MASK) +#define IS_SERVER_BIT(objid) ((LOW_VALUE (objid) & IS_SERVER_MASK) != 0) +#define INSTANCE_BITS(objid) (LOW_VALUE (objid) & INSTANCE_MASK) #endif /** @@ -41,6 +63,20 @@ * Value type representing an object ID, i.e. an object in the remote * application that can be communicated with. * + * An object ID has three parts. 16 bits are provided by the server + * side of a connection, and used for the high 16 bits of all object + * IDs created by the client. 16 bits are provided by the client side + * and used as the next 16 bits of all object IDs created by the + * client. The next single bit is 1 if the object ID represents an + * object on the server side of the connection and 0 otherwise. Then + * 31 bits are provided by the side creating an object instance and + * differ for each instance created (each app should make a best + * effort to avoid recycling the instance values). + * + * 0 is an invalid value for the server bits, the client bits, + * and the object instance bits. An object ID is the null ID + * if all 64 bits are 0. + * * @{ */ @@ -58,8 +94,7 @@ dbus_object_id_equal (const DBusObjectID *a, #ifdef DBUS_HAVE_INT64 return VALUE (a) == VALUE (b); #else - return HIGH_BITS (a) == HIGH_BITS (b) && - LOW_BITS (a) == LOW_BITS (b); + return LOW_VALUE (a) == LOW_VALUE (b) && HIGH_VALUE (a) == HIGH_VALUE (b); #endif } @@ -85,95 +120,168 @@ dbus_object_id_compare (const DBusObjectID *a, else return 0; #else - if (HIGH_BITS (a) > HIGH_BITS (b)) + if (HIGH_VALUE (a) > HIGH_VALUE (b)) return 1; - else if (HIGH_BITS (a) < HIGH_BITS (b)) + else if (HIGH_VALUE (a) < HIGH_VALUE (b)) return -1; - else if (LOW_BITS (a) > LOW_BITS (b)) + else if (LOW_VALUE (a) > LOW_VALUE (b)) return 1; - else if (LOW_BITS (a) < LOW_BITS (b)) + else if (LOW_VALUE (a) < LOW_VALUE (b)) return -1; else return 0; #endif } + /** * An object ID contains 64 bits of data. This function - * returns half of those bits. If you are willing to limit - * portability to compilers with a 64-bit type (this includes - * C99 compilers and almost all other compilers) consider - * dbus_object_id_get_as_integer() instead. + * returns the 16 bits that were provided by the server + * side of the connection. * * @param obj_id the object ID - * @returns the high bits of the ID + * @returns the server bits of the ID * */ -dbus_uint32_t -dbus_object_id_get_high_bits (const DBusObjectID *obj_id) +dbus_uint16_t +dbus_object_id_get_server_bits (const DBusObjectID *obj_id) { - return HIGH_BITS (obj_id); + return SERVER_BITS (obj_id); } /** * An object ID contains 64 bits of data. This function - * returns half of those bits. If you are willing to limit - * portability to compilers with a 64-bit type (this includes - * C99 compilers and almost all other compilers) consider - * dbus_object_id_get_as_integer() instead. + * returns the 16 bits that were provided by the client + * side of the connection. * * @param obj_id the object ID - * @returns the low bits of the ID + * @returns the client bits of the ID * */ -dbus_uint32_t -dbus_object_id_get_low_bits (const DBusObjectID *obj_id) +dbus_uint16_t +dbus_object_id_get_client_bits (const DBusObjectID *obj_id) +{ + return CLIENT_BITS (obj_id); +} + +/** + * An object ID contains 64 bits of data. This function + * returns the bit flagging whether the object ID comes + * from the client or the server side of the connection. + * + * There is no secure guarantee that the bit is accurate; + * object ID values are simply conventional, to make + * collisions relatively unlikely. + * + * @param obj_id the object ID + * @returns the server-side bit of the ID + * + */ +dbus_bool_t +dbus_object_id_get_is_server_bit (const DBusObjectID *obj_id) { - return LOW_BITS (obj_id); + return IS_SERVER_BIT (obj_id); } /** * An object ID contains 64 bits of data. This function - * sets half of those bits. If you are willing to limit - * portability to compilers with a 64-bit type (this includes - * C99 compilers and almost all other compilers) consider - * dbus_object_id_set_as_integer() instead. + * returns the 31 bits that identify the object instance. * * @param obj_id the object ID - * @param value the new value of the high bits + * @returns the instance bits of the ID + * + */ +dbus_uint32_t +dbus_object_id_get_instance_bits (const DBusObjectID *obj_id) +{ + return INSTANCE_BITS (obj_id); +} + +/** + * An object ID contains 64 bits of data. This function sets the 16 + * bits provided by the server side of a connection. + * + * @param obj_id the object ID + * @param value the new value of the server bits * */ void -dbus_object_id_set_high_bits (DBusObjectID *obj_id, - dbus_uint32_t value) +dbus_object_id_set_server_bits (DBusObjectID *obj_id, + dbus_uint16_t value) { #ifdef DBUS_HAVE_INT64 - VALUE (obj_id) = (((dbus_uint64_t) value) << 32) | LOW_BITS (obj_id); + VALUE (obj_id) &= ~ SERVER_MASK; + VALUE (obj_id) |= ((dbus_uint64_t) value) << 48; #else - HIGH_BITS (obj_id) = value; + HIGH_VALUE (obj_id) &= ~ SERVER_MASK; + HIGH_VALUE (obj_id) |= ((dbus_uint32_t) value) << 16; #endif } /** - * An object ID contains 64 bits of data. This function - * sets half of those bits. If you are willing to limit - * portability to compilers with a 64-bit type (this includes - * C99 compilers and almost all other compilers) consider - * dbus_object_id_set_as_integer() instead. + * An object ID contains 64 bits of data. This function sets the 16 + * bits provided by the client side of a connection. * * @param obj_id the object ID - * @param value the new value of the low bits + * @param value the new value of the client bits * */ void -dbus_object_id_set_low_bits (DBusObjectID *obj_id, - dbus_uint32_t value) +dbus_object_id_set_client_bits (DBusObjectID *obj_id, + dbus_uint16_t value) { #ifdef DBUS_HAVE_INT64 - VALUE (obj_id) = ((dbus_uint64_t) value) | - (((dbus_uint64_t) HIGH_BITS (obj_id)) << 32); + VALUE (obj_id) &= ~ CLIENT_MASK; + VALUE (obj_id) |= ((dbus_uint64_t) value) << 32; #else - LOW_BITS (obj_id) = value; + HIGH_VALUE (obj_id) &= ~ CLIENT_MASK; + HIGH_VALUE (obj_id) |= (dbus_uint32_t) value; +#endif +} + +/** + * An object ID contains 64 bits of data. This function sets the + * single bit that flags an instance as server-side or client-side. + * + * @param obj_id the object ID + * @param value the new value of the server-side bit + * + */ +void +dbus_object_id_set_is_server_bit (DBusObjectID *obj_id, + dbus_bool_t value) +{ +#ifdef DBUS_HAVE_INT64 + if (value) + VALUE (obj_id) |= IS_SERVER_MASK; + else + VALUE (obj_id) &= ~ IS_SERVER_MASK; +#else + if (value) + LOW_VALUE (obj_id) |= IS_SERVER_MASK; + else + LOW_VALUE (obj_id) &= ~ IS_SERVER_MASK; +#endif +} + +/** + * An object ID contains 64 bits of data. This function sets the 31 + * bits identifying the object instance. + * + * @param obj_id the object ID + * @param value the new value of the instance bits + * + */ +void +dbus_object_id_set_instance_bits (DBusObjectID *obj_id, + dbus_uint32_t value) +{ +#ifdef DBUS_HAVE_INT64 + VALUE (obj_id) &= ~ INSTANCE_MASK; + VALUE (obj_id) |= (dbus_uint64_t) value; +#else + LOW_VALUE (obj_id) &= ~ INSTANCE_MASK; + LOW_VALUE (obj_id) |= (dbus_uint32_t) value; #endif } @@ -201,7 +309,7 @@ dbus_object_id_is_null (const DBusObjectID *obj_id) #ifdef DBUS_HAVE_INT64 return VALUE (obj_id) == 0; #else - return HIGH_BITS (obj_id) == 0 && LOW_BITS (obj_id) == 0; + return HIGH_VALUE (obj_id) == 0 && LOW_VALUE (obj_id) == 0; #endif } @@ -263,28 +371,49 @@ _dbus_object_id_test (void) DBusObjectID tmp; DBusObjectID tmp2; - dbus_object_id_set_high_bits (&tmp, 340); - _dbus_assert (dbus_object_id_get_high_bits (&tmp) == 340); - - dbus_object_id_set_low_bits (&tmp, 1492); - _dbus_assert (dbus_object_id_get_low_bits (&tmp) == 1492); - _dbus_assert (dbus_object_id_get_high_bits (&tmp) == 340); + /* Check basic get/set */ + dbus_object_id_set_server_bits (&tmp, 340); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); + + dbus_object_id_set_client_bits (&tmp, 1492); + _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); + + dbus_object_id_set_is_server_bit (&tmp, TRUE); + _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); + _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); + + dbus_object_id_set_instance_bits (&tmp, 2001); + _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); + _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); + _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == 2001); + + /* check equality check */ tmp2 = tmp; _dbus_assert (dbus_object_id_equal (&tmp, &tmp2)); - + + /* check get/set as integer */ #ifdef DBUS_HAVE_INT64 _dbus_assert (dbus_object_id_get_as_integer (&tmp) == - ((DBUS_UINT64_CONSTANT (340) << 32) | - DBUS_UINT64_CONSTANT (1492))); + ((DBUS_UINT64_CONSTANT (340) << 48) | + (DBUS_UINT64_CONSTANT (1492) << 32) | + (DBUS_UINT64_CONSTANT (1) << 31) | + (DBUS_UINT64_CONSTANT (2001)))); dbus_object_id_set_as_integer (&tmp, _DBUS_UINT64_MAX); _dbus_assert (dbus_object_id_get_as_integer (&tmp) == _DBUS_UINT64_MAX); - _dbus_assert (dbus_object_id_get_high_bits (&tmp) == - _DBUS_UINT_MAX); - _dbus_assert (dbus_object_id_get_low_bits (&tmp) == - _DBUS_UINT_MAX); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == + 0xffff); + _dbus_assert (dbus_object_id_get_client_bits (&tmp) == + 0xffff); + _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == + TRUE); + _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == + 0x7fffffff); dbus_object_id_set_as_integer (&tmp, 1); dbus_object_id_set_as_integer (&tmp2, 2); @@ -295,24 +424,45 @@ _dbus_object_id_test (void) _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); #endif + /* Check comparison */ tmp2 = tmp; - dbus_object_id_set_high_bits (&tmp, 1); - dbus_object_id_set_high_bits (&tmp2, 2); + dbus_object_id_set_server_bits (&tmp, 1); + dbus_object_id_set_server_bits (&tmp2, 2); _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); - dbus_object_id_set_high_bits (&tmp2, 0); + dbus_object_id_set_server_bits (&tmp2, 0); _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); - dbus_object_id_set_high_bits (&tmp2, 1); + dbus_object_id_set_server_bits (&tmp2, 1); _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); - dbus_object_id_set_low_bits (&tmp, 1); + dbus_object_id_set_client_bits (&tmp, 1); - dbus_object_id_set_low_bits (&tmp2, 2); + dbus_object_id_set_client_bits (&tmp2, 2); _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); - dbus_object_id_set_low_bits (&tmp2, 0); + dbus_object_id_set_client_bits (&tmp2, 0); _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); - dbus_object_id_set_low_bits (&tmp2, 1); + dbus_object_id_set_client_bits (&tmp2, 1); _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); + + /* Check get/set again with high-limit numbers */ + + dbus_object_id_set_server_bits (&tmp, 0xf0f0); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); + + dbus_object_id_set_client_bits (&tmp, 0xf00f); + _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); + + dbus_object_id_set_is_server_bit (&tmp, TRUE); + _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); + _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); + + dbus_object_id_set_instance_bits (&tmp, 0x7fffffff); + _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f); + _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); + _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); + _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == 0x7fffffff); return TRUE; } diff --git a/dbus/dbus-objectid.h b/dbus/dbus-objectid.h index ad8ea1c5..9539f9be 100644 --- a/dbus/dbus-objectid.h +++ b/dbus/dbus-objectid.h @@ -39,23 +39,31 @@ struct DBusObjectID #ifdef DBUS_HAVE_INT64 dbus_uint64_t dbus_do_not_use_dummy1; #else - dbus_uint32_t dbus_do_not_use_dummy1; dbus_uint32_t dbus_do_not_use_dummy2; + dbus_uint32_t dbus_do_not_use_dummy3; #endif }; -dbus_bool_t dbus_object_id_equal (const DBusObjectID *a, - const DBusObjectID *b); -int dbus_object_id_compare (const DBusObjectID *a, - const DBusObjectID *b); -dbus_uint32_t dbus_object_id_get_high_bits (const DBusObjectID *obj_id); -dbus_uint32_t dbus_object_id_get_low_bits (const DBusObjectID *obj_id); -void dbus_object_id_set_high_bits (DBusObjectID *obj_id, - dbus_uint32_t value); -void dbus_object_id_set_low_bits (DBusObjectID *obj_id, - dbus_uint32_t value); -void dbus_object_id_set_null (DBusObjectID *obj_id); -dbus_bool_t dbus_object_id_is_null (const DBusObjectID *obj_id); +dbus_bool_t dbus_object_id_equal (const DBusObjectID *a, + const DBusObjectID *b); +int dbus_object_id_compare (const DBusObjectID *a, + const DBusObjectID *b); +dbus_uint16_t dbus_object_id_get_server_bits (const DBusObjectID *obj_id); +dbus_uint16_t dbus_object_id_get_client_bits (const DBusObjectID *obj_id); +dbus_uint32_t dbus_object_id_get_connection_bits (const DBusObjectID *obj_id); +dbus_bool_t dbus_object_id_get_is_server_bit (const DBusObjectID *obj_id); +dbus_uint32_t dbus_object_id_get_instance_bits (const DBusObjectID *obj_id); +void dbus_object_id_set_server_bits (DBusObjectID *obj_id, + dbus_uint16_t value); +void dbus_object_id_set_client_bits (DBusObjectID *obj_id, + dbus_uint16_t value); +void dbus_object_id_set_is_server_bit (DBusObjectID *obj_id, + dbus_bool_t value); +void dbus_object_id_set_instance_bits (DBusObjectID *obj_id, + dbus_uint32_t value); +void dbus_object_id_set_null (DBusObjectID *obj_id); +dbus_bool_t dbus_object_id_is_null (const DBusObjectID *obj_id); + #ifdef DBUS_HAVE_INT64 dbus_uint64_t dbus_object_id_get_as_integer (const DBusObjectID *obj_id); void dbus_object_id_set_as_integer (DBusObjectID *obj_id, diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 82bb6e3c..04988862 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -60,8 +60,15 @@ extern "C" { /* Max length in bytes of a service or message name */ #define DBUS_MAXIMUM_NAME_LENGTH 256 +/* Types of message */ +#define DBUS_MESSAGE_TYPE_METHOD_CALL 1 +#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 +#define DBUS_MESSAGE_TYPE_ERROR 3 +#define DBUS_MESSAGE_TYPE_SIGNAL 4 + /* Header flags */ -#define DBUS_HEADER_FLAG_ERROR 0x1 +#define DBUS_HEADER_FLAG_ERROR 0x1 +#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x2 /* Header fields */ #define DBUS_HEADER_FIELD_NAME "name" diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index c6f929a8..60c25461 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -964,7 +964,7 @@ _dbus_string_append_8_aligned (DBusString *str, p = (dbus_uint64_t*) (real->str + (real->len - 8)); *p = *((dbus_uint64_t*)octets); #else - char *p; + unsigned char *p; DBUS_STRING_PREAMBLE (str); if (!align_length_then_lengthen (str, 8, 8)) -- cgit From 9c5d01f0fe1ba855c0f7518c4f27d75a609b8faa Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 2 Aug 2003 03:39:35 +0000 Subject: 2003-08-01 Havoc Pennington * dbus/dbus-object-registry.c (_dbus_object_registry_handle_and_unlock): implement * dbus/dbus-message.c (dbus_message_get_type): new function * doc/dbus-specification.sgml: add "type" byte to messages --- dbus/dbus-bus.c | 16 ++-- dbus/dbus-connection.c | 6 +- dbus/dbus-message-builder.c | 8 +- dbus/dbus-message.c | 174 +++++++++++++++++++++++++++++++++----------- dbus/dbus-message.h | 16 ++-- dbus/dbus-object-registry.c | 85 +++++++++++++++++++++- dbus/dbus-object.c | 5 +- dbus/dbus-protocol.h | 1 + 8 files changed, 247 insertions(+), 64 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 6ab1eccc..214978da 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -398,8 +398,8 @@ dbus_bus_register (DBusConnection *connection, return TRUE; } - message = dbus_message_new (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, + DBUS_SERVICE_DBUS); if (!message) @@ -516,8 +516,8 @@ 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 (DBUS_MESSAGE_ACQUIRE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_ACQUIRE_SERVICE, + DBUS_SERVICE_DBUS); if (message == NULL) @@ -590,8 +590,8 @@ 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 (DBUS_MESSAGE_SERVICE_EXISTS, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_SERVICE_EXISTS, + DBUS_SERVICE_DBUS); if (message == NULL) { _DBUS_SET_OOM (error); @@ -652,8 +652,8 @@ dbus_bus_activate_service (DBusConnection *connection, DBusMessage *msg; DBusMessage *reply; - msg = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + msg = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + DBUS_SERVICE_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 4b72d600..ced50bd1 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -722,7 +722,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (io_path_cond == NULL) goto error; - disconnect_message = dbus_message_new (DBUS_MESSAGE_LOCAL_DISCONNECT, NULL); + disconnect_message = dbus_message_new_signal (DBUS_MESSAGE_LOCAL_DISCONNECT); if (disconnect_message == NULL) goto error; @@ -1615,8 +1615,8 @@ dbus_connection_send_with_reply (DBusConnection *connection, dbus_message_handler_ref (reply_handler); - reply = dbus_message_new_error_reply (message, DBUS_ERROR_NO_REPLY, - "No reply within specified time"); + reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, + "No reply within specified time"); if (!reply) { CONNECTION_UNLOCK (connection); diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 390dda75..fc85fc32 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -393,8 +393,14 @@ _dbus_message_data_load (DBusString *dest, goto parse_failed; } + if (!_dbus_string_append_byte (dest, DBUS_MESSAGE_TYPE_METHOD_CALL)) + { + _dbus_warn ("could not append message type\n"); + goto parse_failed; + } + i = 0; - while (i < 3) + while (i < 2) { if (!_dbus_string_append_byte (dest, '\0')) { diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 52226603..c39ca3b4 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -73,6 +73,11 @@ typedef struct */ } HeaderField; +#define BYTE_ORDER_OFFSET 0 +#define TYPE_OFFSET 1 +#define FLAGS_OFFSET 2 +#define VERSION_OFFSET 3 + /** * @brief Internals of DBusMessage * @@ -803,6 +808,7 @@ _dbus_message_remove_size_counter (DBusMessage *message, static dbus_bool_t dbus_message_create_header (DBusMessage *message, + int type, const char *name, const char *service) { @@ -811,6 +817,9 @@ dbus_message_create_header (DBusMessage *message, if (!_dbus_string_append_byte (&message->header, message->byte_order)) return FALSE; + if (!_dbus_string_append_byte (&message->header, type)) + return FALSE; + flags = 0; if (!_dbus_string_append_byte (&message->header, flags)) return FALSE; @@ -818,9 +827,6 @@ dbus_message_create_header (DBusMessage *message, if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION)) return FALSE; - if (!_dbus_string_append_byte (&message->header, 0)) - return FALSE; - message->header_fields[FIELD_HEADER_LENGTH].offset = 4; if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0)) return FALSE; @@ -944,10 +950,11 @@ dbus_message_new_empty_header (void) /** - * Constructs a new message. 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). + * Constructs a new message to invoke a method on a remote + * 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). * * @param name name of the message * @param destination_service service that the message should be sent to or #NULL @@ -955,8 +962,8 @@ dbus_message_new_empty_header (void) * @see dbus_message_unref() */ DBusMessage* -dbus_message_new (const char *name, - const char *destination_service) +dbus_message_new_method_call (const char *name, + const char *destination_service) { DBusMessage *message; @@ -966,7 +973,9 @@ dbus_message_new (const char *name, if (message == NULL) return NULL; - if (!dbus_message_create_header (message, name, destination_service)) + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_METHOD_CALL, + name, destination_service)) { dbus_message_unref (message); return NULL; @@ -976,37 +985,43 @@ dbus_message_new (const char *name, } /** - * Constructs a message that is a reply to some other - * message. Returns #NULL if memory can't be allocated - * for the message. + * Constructs a message that is a reply to a method call. Returns + * #NULL if memory can't be allocated for the message. * - * @param original_message the message which the created + * @param method_call the message which the created * message is a reply to. * @returns a new DBusMessage, free with dbus_message_unref() - * @see dbus_message_new(), dbus_message_unref() + * @see dbus_message_new_method_call(), dbus_message_unref() */ DBusMessage* -dbus_message_new_reply (DBusMessage *original_message) +dbus_message_new_method_return (DBusMessage *method_call) { DBusMessage *message; const char *sender, *name; - _dbus_return_val_if_fail (original_message != NULL, NULL); + _dbus_return_val_if_fail (method_call != NULL, NULL); - sender = get_string_field (original_message, + sender = get_string_field (method_call, FIELD_SENDER, NULL); - name = get_string_field (original_message, + name = get_string_field (method_call, FIELD_NAME, NULL); /* sender is allowed to be null here in peer-to-peer case */ - - message = dbus_message_new (name, sender); - + + message = dbus_message_new_empty_header (); if (message == NULL) return NULL; + + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_METHOD_RETURN, + name, sender)) + { + dbus_message_unref (message); + return NULL; + } if (!dbus_message_set_reply_serial (message, - dbus_message_get_serial (original_message))) + dbus_message_get_serial (method_call))) { dbus_message_unref (message); return NULL; @@ -1015,41 +1030,79 @@ dbus_message_new_reply (DBusMessage *original_message) return message; } +/** + * 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. + * + * @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) +{ + DBusMessage *message; + + _dbus_return_val_if_fail (name != NULL, NULL); + + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_SIGNAL, + name, NULL)) + { + dbus_message_unref (message); + return NULL; + } + + return message; +} + /** * Creates a new message that is an error reply to a certain message. + * Error replies are possible in response to method calls primarily. * - * @param original_message the original message + * @param reply_to the original message * @param error_name the error name * @param error_message the error message string or #NULL for none * @returns a new error message */ DBusMessage* -dbus_message_new_error_reply (DBusMessage *original_message, - const char *error_name, - const char *error_message) +dbus_message_new_error (DBusMessage *reply_to, + const char *error_name, + const char *error_message) { DBusMessage *message; const char *sender; DBusMessageIter iter; - _dbus_return_val_if_fail (original_message != NULL, NULL); + _dbus_return_val_if_fail (reply_to != NULL, NULL); _dbus_return_val_if_fail (error_name != NULL, NULL); - sender = get_string_field (original_message, + sender = get_string_field (reply_to, FIELD_SENDER, NULL); /* sender may be NULL for non-message-bus case or * when the message bus is dealing with an unregistered * connection. */ - - message = dbus_message_new (error_name, sender); - + message = dbus_message_new_empty_header (); if (message == NULL) return NULL; + + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_ERROR, + error_name, sender)) + { + dbus_message_unref (message); + return NULL; + } if (!dbus_message_set_reply_serial (message, - dbus_message_get_serial (original_message))) + dbus_message_get_serial (reply_to))) { dbus_message_unref (message); return NULL; @@ -1200,6 +1253,28 @@ dbus_message_unref (DBusMessage *message) } } +/** + * Gets the type of a message. Types include + * DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_METHOD_RETURN, + * DBUS_MESSAGE_TYPE_ERROR, DBUS_MESSAGE_TYPE_SIGNAL, but other types + * are allowed and all code must silently ignore messages of unknown + * type. DBUS_MESSAGE_TYPE_INVALID will never be returned, however. + * + * + * @param message the message + * @returns the type of the message + */ +int +dbus_message_get_type (DBusMessage *message) +{ + int type; + + type = _dbus_string_get_byte (&message->header, 1); + _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID); + + return type; +} + /** * Gets the name of a message. * @@ -3704,7 +3779,7 @@ dbus_message_set_is_error (DBusMessage *message, _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (!message->locked); - header = _dbus_string_get_data_len (&message->header, 1, 1); + header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1); if (is_error_reply) *header |= DBUS_HEADER_FLAG_ERROR; @@ -3726,7 +3801,7 @@ dbus_message_get_is_error (DBusMessage *message) _dbus_return_val_if_fail (message != NULL, FALSE); - header = _dbus_string_get_const_data_len (&message->header, 1, 1); + header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1); return (*header & DBUS_HEADER_FLAG_ERROR) != 0; } @@ -4298,6 +4373,9 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader, /** * Converts buffered data into messages. * + * @todo we need to check that the proper named header fields exist + * for each message type. + * * @param loader the loader. * @returns #TRUE if we had enough memory to finish. */ @@ -4311,22 +4389,22 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) { DBusMessage *message; const char *header_data; - int byte_order, header_len, body_len, header_padding; + int byte_order, message_type, header_len, body_len, header_padding; dbus_uint32_t header_len_unsigned, body_len_unsigned; header_data = _dbus_string_get_const_data_len (&loader->data, 0, 16); _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data); - if (header_data[2] != DBUS_MAJOR_PROTOCOL_VERSION) + if (header_data[VERSION_OFFSET] != DBUS_MAJOR_PROTOCOL_VERSION) { _dbus_verbose ("Message has protocol version %d ours is %d\n", - (int) header_data[2], DBUS_MAJOR_PROTOCOL_VERSION); + (int) header_data[VERSION_OFFSET], DBUS_MAJOR_PROTOCOL_VERSION); loader->corrupted = TRUE; return TRUE; } - byte_order = header_data[0]; + byte_order = header_data[BYTE_ORDER_OFFSET]; if (byte_order != DBUS_LITTLE_ENDIAN && byte_order != DBUS_BIG_ENDIAN) @@ -4337,6 +4415,18 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) return TRUE; } + /* Unknown types are ignored, but INVALID is + * disallowed + */ + message_type = header_data[TYPE_OFFSET]; + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + _dbus_verbose ("Message with bad type '%d' received\n", + message_type); + loader->corrupted = TRUE; + return TRUE; + } + header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4); body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8); @@ -5821,7 +5911,7 @@ _dbus_message_test (const char *test_data_dir) _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); - message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test"); + message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test")); _dbus_message_set_serial (message, 1234); dbus_message_set_sender (message, "org.foo.bar"); @@ -5840,7 +5930,7 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (message); /* Test the vararg functions */ - message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test"); + message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); _dbus_message_set_serial (message, 1); dbus_message_append_args (message, DBUS_TYPE_INT32, -0x12345678, @@ -5906,7 +5996,7 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (message); dbus_message_unref (copy); - message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test"); + message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); _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 bd52bd1a..d2c14c78 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -57,17 +57,19 @@ struct DBusMessageIter void *pad3; }; +DBusMessage* dbus_message_new_method_call (const char *name, + 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_error (DBusMessage *reply_to, + const char *error_name, + const char *error_message); -DBusMessage* dbus_message_new (const char *name, - const char *destination_service); -DBusMessage* dbus_message_new_reply (DBusMessage *original_message); -DBusMessage* dbus_message_new_error_reply (DBusMessage *original_message, - const char *error_name, - const char *error_message); -DBusMessage *dbus_message_copy (const DBusMessage *message); +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); const char* dbus_message_get_name (DBusMessage *message); const char* dbus_message_get_destination (DBusMessage *message); dbus_bool_t dbus_message_set_sender (DBusMessage *message, diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index a550f8e2..a4d92216 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -24,6 +24,7 @@ #include "dbus-connection-internal.h" #include "dbus-internals.h" #include "dbus-hash.h" +#include "dbus-protocol.h" #include /** @@ -599,12 +600,64 @@ _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, (* vtable->unregistered) (&info); } +/** + * Handle a message, passing it to any objects in the registry that + * should receive it. + * + * @todo handle messages to an object ID, not just those to + * an interface name. + * + * @param registry the object registry + * @param message the message to handle + * @returns what to do with the message next + */ DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, DBusMessage *message) { - /* FIXME */ - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + DBusInterfaceEntry *iface_entry; + DBusObjectEntry *object_entry; + DBusObjectInfo info; + const DBusObjectVTable *vtable; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + + /* If the message isn't to a specific object ID, we send + * it to the first object that supports the given interface. + */ + iface_entry = lookup_interface (registry, + dbus_message_get_name (message), + FALSE); + + if (iface_entry == NULL) + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + + _dbus_assert (iface_entry->n_objects > 0); + _dbus_assert (iface_entry->objects != NULL); + + object_entry = ®istry->entries[iface_entry->objects[0]]; + + + /* Once we have an object entry, pass message to the object */ + + _dbus_assert (object_entry->vtable != NULL); + + info_from_entry (registry, &info, object_entry); + vtable = object_entry->vtable; + + /* Drop lock and invoke application code */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + (* vtable->message) (&info, message); + + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; } void @@ -665,6 +718,7 @@ add_and_remove_objects (DBusObjectRegistry *registry) "org.freedesktop.Test.Foo", NULL }; int i; + DBusMessage *message; i = 0; while (i < N_OBJECTS) @@ -761,6 +815,33 @@ add_and_remove_objects (DBusObjectRegistry *registry) ++i; } + message = dbus_message_new_method_call ("org.freedesktop.Test.Foo", NULL); + if (message != NULL) + { + if (_dbus_object_registry_handle_and_unlock (registry, message) != + DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + _dbus_assert_not_reached ("message not handled\n"); + dbus_message_unref (message); + } + + message = dbus_message_new_method_call ("org.freedesktop.Test.Blah", NULL); + if (message != NULL) + { + if (_dbus_object_registry_handle_and_unlock (registry, message) != + DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + _dbus_assert_not_reached ("message not handled\n"); + dbus_message_unref (message); + } + + message = dbus_message_new_method_call ("org.freedesktop.Test.NotRegisteredIface", NULL); + if (message != NULL) + { + if (_dbus_object_registry_handle_and_unlock (registry, message) != + DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS) + _dbus_assert_not_reached ("message handled but no handler was registered\n"); + dbus_message_unref (message); + } + i = 0; while (i < (N_OBJECTS - 30)) { diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c index c3f1536d..5582f94a 100644 --- a/dbus/dbus-object.c +++ b/dbus/dbus-object.c @@ -273,6 +273,10 @@ dbus_callback_object_set_data (DBusCallbackObject *callback, * Sets the function to be used to handle messages to the * callback object. * + * @todo the thread locking on DBusCallbackObject is hosed; in this + * function in particular it's a joke since we don't take the same + * lock when _calling_ the callback function. + * * @param callback the callback * @param function the function */ @@ -287,7 +291,6 @@ dbus_callback_object_set_function (DBusCallbackObject *callback, _DBUS_UNLOCK (callback_object); } - /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 04988862..dcb7a042 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -61,6 +61,7 @@ extern "C" { #define DBUS_MAXIMUM_NAME_LENGTH 256 /* Types of message */ +#define DBUS_MESSAGE_TYPE_INVALID 0 #define DBUS_MESSAGE_TYPE_METHOD_CALL 1 #define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 #define DBUS_MESSAGE_TYPE_ERROR 3 -- cgit From ff8908f1e98eda82b0a77abb449ecff36abf14aa Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 2 Aug 2003 14:58:33 +0000 Subject: 2003-08-02 Havoc Pennington * dbus/dbus-message.c (dbus_message_get_no_reply) (dbus_message_set_no_reply): add these and remove set_is_error/get_is_error * dbus/dbus-protocol.h, doc/dbus-specification.sgml: remove the ERROR flag, since there's now an ERROR type --- dbus/dbus-message.c | 45 +++++++++++++++++++++++---------------------- dbus/dbus-message.h | 6 +++--- dbus/dbus-protocol.h | 3 +-- 3 files changed, 27 insertions(+), 27 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index c39ca3b4..8ea653f0 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -1117,8 +1117,6 @@ dbus_message_new_error (DBusMessage *reply_to, return NULL; } } - - dbus_message_set_is_error (message, TRUE); return message; } @@ -3764,15 +3762,18 @@ dbus_message_set_sender (DBusMessage *message, } /** - * Sets a flag indicating that the message is an error reply - * message, i.e. an "exception" rather than a normal response. + * Sets a flag indicating that the message does not want a reply; if + * this flag is set, the other end of the connection may (but is not + * required to) optimize by not sending method return or error + * replies. If this flag is set, there is no way to know whether the + * message successfully arrived at the remote end. * * @param message the message - * @param is_error_reply #TRUE if this is an error message. + * @param no_reply #TRUE if no reply is desired */ void -dbus_message_set_is_error (DBusMessage *message, - dbus_bool_t is_error_reply) +dbus_message_set_no_reply (DBusMessage *message, + dbus_bool_t no_reply) { char *header; @@ -3781,21 +3782,21 @@ dbus_message_set_is_error (DBusMessage *message, header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1); - if (is_error_reply) - *header |= DBUS_HEADER_FLAG_ERROR; + if (no_reply) + *header |= DBUS_HEADER_FLAG_NO_REPLY_EXPECTED; else - *header &= ~DBUS_HEADER_FLAG_ERROR; + *header &= ~DBUS_HEADER_FLAG_NO_REPLY_EXPECTED; } /** - * Returns #TRUE if the message is an error - * reply to some previous message we sent. + * Returns #TRUE if the message does not expect + * a reply. * * @param message the message - * @returns #TRUE if the message is an error + * @returns #TRUE if the message sender isn't waiting for a reply */ dbus_bool_t -dbus_message_get_is_error (DBusMessage *message) +dbus_message_get_no_reply (DBusMessage *message) { const char *header; @@ -3803,7 +3804,7 @@ dbus_message_get_is_error (DBusMessage *message) header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1); - return (*header & DBUS_HEADER_FLAG_ERROR) != 0; + return (*header & DBUS_HEADER_FLAG_NO_REPLY_EXPECTED) != 0; } /** @@ -3908,7 +3909,7 @@ dbus_message_has_sender (DBusMessage *message, /** * Sets a #DBusError based on the contents of the given * message. The error is only set if the message - * is an error message, as in dbus_message_get_is_error(). + * is an error message, as in DBUS_MESSAGE_TYPE_ERROR. * The name of the error is set to the name of the message, * and the error message is set to the first argument * if the argument exists and is a string. @@ -3931,7 +3932,7 @@ dbus_set_error_from_message (DBusError *error, _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); - if (!dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) return FALSE; str = NULL; @@ -5921,11 +5922,11 @@ _dbus_message_test (const char *test_data_dir) _dbus_assert (dbus_message_get_serial (message) == 1234); _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test")); - _dbus_assert (dbus_message_get_is_error (message) == FALSE); - dbus_message_set_is_error (message, TRUE); - _dbus_assert (dbus_message_get_is_error (message) == TRUE); - dbus_message_set_is_error (message, FALSE); - _dbus_assert (dbus_message_get_is_error (message) == FALSE); + _dbus_assert (dbus_message_get_no_reply (message) == FALSE); + dbus_message_set_no_reply (message, TRUE); + _dbus_assert (dbus_message_get_no_reply (message) == TRUE); + dbus_message_set_no_reply (message, FALSE); + _dbus_assert (dbus_message_get_no_reply (message) == FALSE); dbus_message_unref (message); diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index d2c14c78..de5dc833 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -75,9 +75,9 @@ const char* dbus_message_get_destination (DBusMessage *message); dbus_bool_t dbus_message_set_sender (DBusMessage *message, const char *sender); const char* dbus_message_get_sender (DBusMessage *message); -void dbus_message_set_is_error (DBusMessage *message, - dbus_bool_t is_error_reply); -dbus_bool_t dbus_message_get_is_error (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, const char *name); dbus_bool_t dbus_message_has_destination (DBusMessage *message, diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index dcb7a042..e027cf56 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -68,8 +68,7 @@ extern "C" { #define DBUS_MESSAGE_TYPE_SIGNAL 4 /* Header flags */ -#define DBUS_HEADER_FLAG_ERROR 0x1 -#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x2 +#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1 /* Header fields */ #define DBUS_HEADER_FIELD_NAME "name" -- cgit From cefb84edc5f84011c5a171e5d052e37c56c55d27 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 7 Aug 2003 02:18:54 +0000 Subject: 2003-08-06 Havoc Pennington * dbus/dbus-object-registry.c: implement signal connection and dispatch * dbus/dbus-connection.c (_dbus_connection_unref_unlocked): new * dbus/dbus-internals.c (_dbus_memdup): new function --- dbus/dbus-connection-internal.h | 1 + dbus/dbus-connection.c | 48 +++- dbus/dbus-internals.c | 27 +- dbus/dbus-internals.h | 2 + dbus/dbus-object-registry.c | 617 +++++++++++++++++++++++++++++++++++----- dbus/dbus-object-registry.h | 8 +- dbus/dbus-object.h | 5 +- 7 files changed, 628 insertions(+), 80 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 5bcbcc2f..423df5f8 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -42,6 +42,7 @@ typedef enum void _dbus_connection_lock (DBusConnection *connection); void _dbus_connection_unlock (DBusConnection *connection); void _dbus_connection_ref_unlocked (DBusConnection *connection); +void _dbus_connection_unref_unlocked (DBusConnection *connection); dbus_bool_t _dbus_connection_queue_received_message (DBusConnection *connection, DBusMessage *message); void _dbus_connection_queue_received_message_link (DBusConnection *connection, diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ced50bd1..407b4d24 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -203,7 +203,7 @@ static void _dbus_connection_remove_timeout_locked (DB static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection); static void _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection, DBusDispatchStatus new_status); - +static void _dbus_connection_last_unref (DBusConnection *connection); /** @@ -824,6 +824,39 @@ _dbus_connection_ref_unlocked (DBusConnection *connection) #endif } +/** + * Decrements the reference count of a DBusConnection. + * Requires that the caller already holds the connection lock. + * + * @param connection the connection. + */ +void +_dbus_connection_unref_unlocked (DBusConnection *connection) +{ + dbus_bool_t last_unref; + + _dbus_return_if_fail (connection != NULL); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ + +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&connection->refcount) == 1); +#else + _dbus_assert (connection->refcount.value > 0); + + connection->refcount.value -= 1; + last_unref = (connection->refcount.value == 0); +#if 0 + printf ("unref_unlocked() connection %p count = %d\n", connection, connection->refcount.value); +#endif +#endif + + if (last_unref) + _dbus_connection_last_unref (connection); +} + static dbus_uint32_t _dbus_connection_get_next_client_serial (DBusConnection *connection) { @@ -2215,6 +2248,8 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) * does not necessarily dispatch a message, as the data may * be part of authentication or the like. * + * @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY + * * @param connection the connection * @returns dispatch status */ @@ -2310,7 +2345,7 @@ dbus_connection_dispatch (DBusConnection *connection) result = _dbus_message_handler_handle_message (handler, connection, message); - if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + if (result != DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS) break; link = next; @@ -2323,6 +2358,9 @@ dbus_connection_dispatch (DBusConnection *connection) CONNECTION_LOCK (connection); + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + /* FIXME */ ; + /* Did a reply we were waiting on get filtered? */ if (reply_handler_data && result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) { @@ -2342,7 +2380,7 @@ dbus_connection_dispatch (DBusConnection *connection) if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) goto out; - + if (reply_handler_data) { CONNECTION_UNLOCK (connection); @@ -2364,9 +2402,13 @@ dbus_connection_dispatch (DBusConnection *connection) result = _dbus_object_registry_handle_and_unlock (connection->objects, message); + CONNECTION_LOCK (connection); if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) goto out; + + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + /* FIXME */ ; _dbus_verbose (" done dispatching %p (%s) on connection %p\n", message, dbus_message_get_name (message), connection); diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 6e7f9e16..ccc11776 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -248,7 +248,7 @@ _dbus_verbose_reset_real (void) char* _dbus_strdup (const char *str) { - int len; + size_t len; char *copy; if (str == NULL) @@ -265,6 +265,31 @@ _dbus_strdup (const char *str) return copy; } +#ifdef DBUS_BUILD_TESTS /* memdup not used at the moment */ +/** + * Duplicates a block of memory. Returns + * #NULL on failure. + * + * @param mem memory to copy + * @param n_bytes number of bytes to copy + * @returns the copy + */ +void* +_dbus_memdup (const void *mem, + size_t n_bytes) +{ + void *copy; + + copy = dbus_malloc (n_bytes); + if (copy == NULL) + return NULL; + + memcpy (copy, mem, n_bytes); + + return copy; +} +#endif + /** * Duplicates a string array. Result may be freed with * dbus_free_string_array(). Returns #NULL if memory allocation fails. diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 7acda71a..6d120f1b 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -144,6 +144,8 @@ extern const char _dbus_return_if_fail_warning_format[]; ((void*)_DBUS_ALIGN_VALUE(this, boundary)) char* _dbus_strdup (const char *str); +void* _dbus_memdup (const void *mem, + size_t n_bytes); dbus_bool_t _dbus_string_array_contains (const char **array, const char *str); char** _dbus_dup_string_array (const char **array); diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index a4d92216..55f8f749 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -35,11 +35,16 @@ * Types and functions related to DBusObjectRegistry. These * are all internal. * + * @todo interface entries and signal connections are handled pretty + * much identically, with lots of duplicate code. Once we're sure + * they will always be the same, we could merge this code. + * * @{ */ typedef struct DBusObjectEntry DBusObjectEntry; typedef struct DBusInterfaceEntry DBusInterfaceEntry; +typedef struct DBusSignalEntry DBusSignalEntry; #define DBUS_MAX_OBJECTS_PER_INTERFACE 65535 struct DBusInterfaceEntry @@ -50,6 +55,17 @@ struct DBusInterfaceEntry char name[4]; /**< Name of interface (actually allocated larger) */ }; +#define DBUS_MAX_CONNECTIONS_PER_SIGNAL 65535 +struct DBusSignalEntry +{ + unsigned int n_connections : 16; /**< Number of connections to this signal */ + unsigned int n_allocated : 16; /**< Allocated size of objects array */ + dbus_uint16_t *connections; /**< Index of each object connected (can have dups for multiple + * connections) + */ + char name[4]; /**< Name of signal (actually allocated larger) */ +}; + /* 14 bits for object index, 32K objects */ #define DBUS_OBJECT_INDEX_BITS (14) #define DBUS_OBJECT_INDEX_MASK (0x3fff) @@ -62,6 +78,7 @@ struct DBusObjectEntry void *object_impl; /**< Pointer to application-supplied implementation */ const DBusObjectVTable *vtable; /**< Virtual table for this object */ DBusInterfaceEntry **interfaces; /**< NULL-terminated list of interfaces */ + DBusSignalEntry **signals; /**< Signal connections (contains dups, one each time we connect) */ }; struct DBusObjectRegistry @@ -74,6 +91,8 @@ struct DBusObjectRegistry int n_entries_used; DBusHashTable *interface_table; + + DBusHashTable *signal_table; }; static void @@ -88,11 +107,24 @@ free_interface_entry (void *entry) dbus_free (iface); } +static void +free_signal_entry (void *entry) +{ + DBusSignalEntry *signal = entry; + + if (signal == NULL) /* DBusHashTable stupidity */ + return; + + dbus_free (signal->connections); + dbus_free (signal); +} + DBusObjectRegistry* _dbus_object_registry_new (DBusConnection *connection) { DBusObjectRegistry *registry; DBusHashTable *interface_table; + DBusHashTable *signal_table; /* the connection passed in here isn't fully constructed, * so don't do anything more than store a pointer to @@ -101,6 +133,7 @@ _dbus_object_registry_new (DBusConnection *connection) registry = NULL; interface_table = NULL; + signal_table = NULL; registry = dbus_new0 (DBusObjectRegistry, 1); if (registry == NULL) @@ -110,10 +143,16 @@ _dbus_object_registry_new (DBusConnection *connection) NULL, free_interface_entry); if (interface_table == NULL) goto oom; + + signal_table = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, free_signal_entry); + if (signal_table == NULL) + goto oom; registry->refcount = 1; registry->connection = connection; registry->interface_table = interface_table; + registry->signal_table = signal_table; return registry; @@ -122,7 +161,9 @@ _dbus_object_registry_new (DBusConnection *connection) dbus_free (registry); if (interface_table) _dbus_hash_table_unref (interface_table); - + if (signal_table) + _dbus_hash_table_unref (signal_table); + return NULL; } @@ -147,16 +188,20 @@ _dbus_object_registry_unref (DBusObjectRegistry *registry) _dbus_assert (registry->n_entries_used == 0); _dbus_assert (_dbus_hash_table_get_n_entries (registry->interface_table) == 0); + _dbus_assert (_dbus_hash_table_get_n_entries (registry->signal_table) == 0); i = 0; while (i < registry->n_entries_allocated) { if (registry->entries[i].interfaces) dbus_free (registry->entries[i].interfaces); + if (registry->entries[i].signals) + dbus_free (registry->entries[i].signals); ++i; } _dbus_hash_table_unref (registry->interface_table); + _dbus_hash_table_unref (registry->signal_table); dbus_free (registry->entries); dbus_free (registry); } @@ -213,32 +258,41 @@ validate_id (DBusObjectRegistry *registry, } static void -info_from_entry (DBusObjectRegistry *registry, - DBusObjectInfo *info, - DBusObjectEntry *entry) +id_from_entry (DBusObjectRegistry *registry, + DBusObjectID *object_id, + DBusObjectEntry *entry) { - info->connection = registry->connection; - info->object_impl = entry->object_impl; #ifdef DBUS_BUILD_TESTS if (registry->connection) #endif _dbus_connection_init_id (registry->connection, - &info->object_id); + object_id); #ifdef DBUS_BUILD_TESTS else { - dbus_object_id_set_server_bits (&info->object_id, 1); - dbus_object_id_set_client_bits (&info->object_id, 2); + dbus_object_id_set_server_bits (object_id, 1); + dbus_object_id_set_client_bits (object_id, 2); } #endif - _dbus_assert (dbus_object_id_get_server_bits (&info->object_id) != 0); - _dbus_assert (dbus_object_id_get_client_bits (&info->object_id) != 0); + _dbus_assert (dbus_object_id_get_server_bits (object_id) != 0); + _dbus_assert (dbus_object_id_get_client_bits (object_id) != 0); - dbus_object_id_set_instance_bits (&info->object_id, + dbus_object_id_set_instance_bits (object_id, ENTRY_TO_ID (entry)); - _dbus_assert (dbus_object_id_get_instance_bits (&info->object_id) != 0); + _dbus_assert (dbus_object_id_get_instance_bits (object_id) != 0); +} + +static void +info_from_entry (DBusObjectRegistry *registry, + DBusObjectInfo *info, + DBusObjectEntry *entry) +{ + info->connection = registry->connection; + info->object_impl = entry->object_impl; + + id_from_entry (registry, &info->object_id, entry); } static DBusInterfaceEntry* @@ -375,6 +429,483 @@ object_remove_from_interfaces (DBusObjectRegistry *registry, } } +static DBusSignalEntry* +lookup_signal (DBusObjectRegistry *registry, + const char *name, + dbus_bool_t create_if_not_found) +{ + DBusSignalEntry *entry; + int sz; + int len; + + entry = _dbus_hash_table_lookup_string (registry->signal_table, + name); + 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; + 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); + + if (!_dbus_hash_table_insert_string (registry->signal_table, + entry->name, entry)) + { + dbus_free (entry); + return NULL; + } + + return entry; +} + +static void +delete_signal (DBusObjectRegistry *registry, + DBusSignalEntry *entry) +{ + _dbus_hash_table_remove_string (registry->signal_table, + entry->name); +} + +static dbus_bool_t +signal_entry_add_object (DBusSignalEntry *entry, + dbus_uint16_t object_index) +{ + if (entry->n_connections == entry->n_allocated) + { + unsigned int new_alloc; + dbus_uint16_t *new_objects; + + if (entry->n_allocated == 0) + new_alloc = 2; + else + new_alloc = entry->n_allocated * 2; + + /* Right now MAX_CONNECTIONS_PER_SIGNAL can't possibly be reached + * since the max number of objects _total_ is smaller, but the + * code is here for future robustness. + */ + + if (new_alloc > DBUS_MAX_CONNECTIONS_PER_SIGNAL) + new_alloc = DBUS_MAX_CONNECTIONS_PER_SIGNAL; + if (new_alloc == entry->n_allocated) + { + _dbus_warn ("Attempting to register another instance with signal %s, but max count %d reached\n", + entry->name, DBUS_MAX_CONNECTIONS_PER_SIGNAL); + return FALSE; + } + + new_objects = dbus_realloc (entry->connections, new_alloc * sizeof (dbus_uint16_t)); + if (new_objects == NULL) + return FALSE; + entry->connections = new_objects; + entry->n_allocated = new_alloc; + } + + _dbus_assert (entry->n_connections < entry->n_allocated); + + entry->connections[entry->n_connections] = object_index; + entry->n_connections += 1; + + return TRUE; +} + +static void +signal_entry_remove_object (DBusSignalEntry *entry, + dbus_uint16_t object_index) +{ + unsigned int i; + + i = 0; + while (i < entry->n_connections) + { + if (entry->connections[i] == object_index) + break; + ++i; + } + + if (i == entry->n_connections) + { + _dbus_assert_not_reached ("Tried to remove object from an signal that didn't list that object\n"); + return; + } + + memmove (&entry->connections[i], + &entry->connections[i+1], + (entry->n_connections - i - 1) * sizeof (entry->connections[0])); + entry->n_connections -= 1; +} + +static void +object_remove_from_signals (DBusObjectRegistry *registry, + DBusObjectEntry *entry) +{ + if (entry->signals != NULL) + { + int i; + + i = 0; + while (entry->signals[i] != NULL) + { + DBusSignalEntry *iface = entry->signals[i]; + + signal_entry_remove_object (iface, entry->id_index); + if (iface->n_connections == 0) + delete_signal (registry, iface); + ++i; + } + } +} + +/** + * Connect this object to the given signal, such that if a + * signal emission message is received with the given + * signal name, the message will be routed to the + * given object. + * + * Must be called with #DBusConnection lock held. + * + * @param registry the object registry + * @param object_id object that would like to see the signal + * @param signal signal name + * + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_object_registry_connect_locked (DBusObjectRegistry *registry, + const DBusObjectID *object_id, + const char *signal_name) +{ + DBusSignalEntry **new_signals; + DBusSignalEntry *signal; + DBusObjectEntry *entry; + int i; + + entry = validate_id (registry, object_id); + if (entry == NULL) + { + _dbus_warn ("Tried to connect a nonexistent D-BUS object ID to signal \"%s\"\n", + signal_name); + + return FALSE; + } + + /* O(n) in number of connections unfortunately, but in practice I + * don't think it will matter. It's marginally a space-time + * tradeoff (save an n_signals field) but the NULL termination is + * just as large as an n_signals once we have even a single + * connection. + */ + i = 0; + if (entry->signals != NULL) + { + while (entry->signals[i] != NULL) + ++i; + } + + new_signals = dbus_realloc (entry->signals, + (i + 2) * sizeof (DBusSignalEntry*)); + + if (new_signals == NULL) + return FALSE; + + entry->signals = new_signals; + + signal = lookup_signal (registry, signal_name, TRUE); + if (signal == NULL) + goto oom; + + if (!signal_entry_add_object (signal, entry->id_index)) + goto oom; + + entry->signals[i] = signal; + ++i; + entry->signals[i] = NULL; + + return TRUE; + + oom: + if (signal && signal->n_connections == 0) + delete_signal (registry, signal); + + return FALSE; +} + +/** + * Reverses effects of _dbus_object_registry_disconnect_locked(). + * + * @param registry the object registry + * @param object_id object that would like to see the signal + * @param signal signal name + */ +void +_dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry, + const DBusObjectID *object_id, + const char *signal_name) +{ + DBusObjectEntry *entry; + DBusSignalEntry *signal; + + 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); + + return; + } + + signal = lookup_signal (registry, signal_name, FALSE); + if (signal == NULL) + { + _dbus_warn ("Tried to disconnect signal \"%s\" but no such signal is connected\n", + signal_name); + return; + } + + signal_entry_remove_object (signal, entry->id_index); + + if (signal->n_connections == 0) + delete_signal (registry, signal); +} + +static DBusHandlerResult +handle_method_call_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + DBusInterfaceEntry *iface_entry; + DBusObjectEntry *object_entry; + DBusObjectInfo info; + const DBusObjectVTable *vtable; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + /* FIXME handle calls to an object ID instead of just an + * interface name + */ + + /* If the message isn't to a specific object ID, we send + * it to the first object that supports the given interface. + */ + iface_entry = lookup_interface (registry, + dbus_message_get_name (message), + FALSE); + + if (iface_entry == NULL) + { +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + } + + _dbus_assert (iface_entry->n_objects > 0); + _dbus_assert (iface_entry->objects != NULL); + + object_entry = ®istry->entries[iface_entry->objects[0]]; + + + /* Once we have an object entry, pass message to the object */ + + _dbus_assert (object_entry->vtable != NULL); + + info_from_entry (registry, &info, object_entry); + vtable = object_entry->vtable; + + /* Drop lock and invoke application code */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + (* vtable->message) (&info, message); + + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; +} + +typedef struct +{ + DBusObjectID id; +} ObjectEmitData; + +static DBusHandlerResult +handle_signal_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + DBusSignalEntry *signal_entry; + int i; + ObjectEmitData *objects; + int n_objects; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + signal_entry = lookup_signal (registry, + dbus_message_get_name (message), + FALSE); + + if (signal_entry == NULL) + { +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + } + + _dbus_assert (signal_entry->n_connections > 0); + _dbus_assert (signal_entry->connections != NULL); + + /* make a copy for safety vs. reentrancy */ + + /* FIXME (?) if you disconnect a signal during (vs. before) + * emission, you still receive that signal. To fix this uses more + * memory because we don't have a per-connection object at the + * moment. You would have to introduce a connection object and + * refcount it and have a "disconnected" flag. This is more like + * GObject semantics but also maybe not important at this level (the + * GObject/Qt wrappers can mop it up). + */ + + n_objects = signal_entry->n_connections; + objects = dbus_new (ObjectEmitData, n_objects); + + if (objects == NULL) + { +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + i = 0; + while (i < signal_entry->n_connections) + { + DBusObjectEntry *object_entry; + int idx; + + idx = signal_entry->connections[i]; + + object_entry = ®istry->entries[idx]; + + _dbus_assert (object_entry->vtable != NULL); + + id_from_entry (registry, + &objects[i].id, + object_entry); + + ++i; + } + +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_ref_unlocked (registry->connection); + _dbus_object_registry_ref (registry); + dbus_message_ref (message); + + i = 0; + while (i < n_objects) + { + DBusObjectEntry *object_entry; + + /* If an object ID no longer exists, don't send the + * signal + */ + object_entry = validate_id (registry, &objects[i].id); + if (object_entry != NULL) + { + DBusObjectVTable *vtable; + DBusObjectInfo info; + + info_from_entry (registry, &info, object_entry); + vtable = object_entry->vtable; + + /* Drop lock and invoke application code */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + (* vtable->message) (&info, message); + + /* Reacquire lock */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_lock (registry->connection); + } + ++i; + } + + dbus_message_unref (message); + _dbus_object_registry_unref (registry); +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unref_unlocked (registry->connection); + + dbus_free (objects); + + /* Drop lock a final time */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; +} + +/** + * Handle a message, passing it to any objects in the registry that + * should receive it. + * + * @todo handle messages to an object ID, not just those to + * an interface name. + * + * @param registry the object registry + * @param message the message to handle + * @returns what to do with the message next + */ +DBusHandlerResult +_dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + int type; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + type = dbus_message_get_type (message); + + switch (type) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return handle_method_call_and_unlock (registry, message); + case DBUS_MESSAGE_TYPE_SIGNAL: + return handle_signal_and_unlock (registry, message); + default: +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + } +} + dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, const char **interfaces, @@ -583,6 +1114,7 @@ _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, return; } + object_remove_from_signals (registry, entry); object_remove_from_interfaces (registry, entry); info_from_entry (registry, &info, entry); @@ -600,65 +1132,6 @@ _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, (* vtable->unregistered) (&info); } -/** - * Handle a message, passing it to any objects in the registry that - * should receive it. - * - * @todo handle messages to an object ID, not just those to - * an interface name. - * - * @param registry the object registry - * @param message the message to handle - * @returns what to do with the message next - */ -DBusHandlerResult -_dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, - DBusMessage *message) -{ - DBusInterfaceEntry *iface_entry; - DBusObjectEntry *object_entry; - DBusObjectInfo info; - const DBusObjectVTable *vtable; - - _dbus_assert (registry != NULL); - _dbus_assert (message != NULL); - - if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - - /* If the message isn't to a specific object ID, we send - * it to the first object that supports the given interface. - */ - iface_entry = lookup_interface (registry, - dbus_message_get_name (message), - FALSE); - - if (iface_entry == NULL) - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; - - _dbus_assert (iface_entry->n_objects > 0); - _dbus_assert (iface_entry->objects != NULL); - - object_entry = ®istry->entries[iface_entry->objects[0]]; - - - /* Once we have an object entry, pass message to the object */ - - _dbus_assert (object_entry->vtable != NULL); - - info_from_entry (registry, &info, object_entry); - vtable = object_entry->vtable; - - /* Drop lock and invoke application code */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - (* vtable->message) (&info, message); - - return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; -} void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) diff --git a/dbus/dbus-object-registry.h b/dbus/dbus-object-registry.h index 57009c87..bcbd0f84 100644 --- a/dbus/dbus-object-registry.h +++ b/dbus/dbus-object-registry.h @@ -43,8 +43,12 @@ void _dbus_object_registry_remove_and_unlock (DBusObjectRegistry DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, DBusMessage *message); 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); +void _dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry, + const DBusObjectID *object_id, + const char *signal); DBUS_END_DECLS; diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h index a0a53eb0..76d0e6f6 100644 --- a/dbus/dbus-object.h +++ b/dbus/dbus-object.h @@ -41,8 +41,9 @@ typedef struct DBusCallbackObject DBusCallbackObject; typedef enum { - DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */ - DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS /**< Run any additional handlers that are interested in this message. */ + DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */ + DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS, /**< Run any additional handlers that are interested in this message. */ + DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory to handle this message. */ } DBusHandlerResult; struct DBusObjectInfo -- cgit From b29ea9115ea3277354b7ccbe442026279220f4ac Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 11 Aug 2003 02:11:58 +0000 Subject: 2003-08-10 Havoc Pennington * tools/dbus-send.c (main): add --type argument, for now supporting only method_call and signal types. * tools/dbus-print-message.c: print message type * dbus/dbus-connection.c (_dbus_connection_new_for_transport): init connection->objects * doc/dbus-specification.sgml: fix sgml * bus/*.c: port over to object-instance API changes * test/test-service.c: ditto * dbus/dbus-message.c (dbus_message_create_header): allow #NULL name, we will have to fix up the rest of the code to also handle this (dbus_message_new): generic message-creation call (set_string_field): allow appending name field --- dbus/dbus-connection.c | 1 + dbus/dbus-message.c | 106 +++++++++++++++++++++++++++++++++++++++++--- dbus/dbus-message.h | 5 +++ dbus/dbus-object-registry.c | 2 +- 4 files changed, 107 insertions(+), 7 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 407b4d24..d30ccb0a 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -753,6 +753,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) connection->outgoing_counter = outgoing_counter; connection->filter_list = NULL; connection->last_dispatch_status = DBUS_DISPATCH_COMPLETE; /* so we're notified first time there's data */ + connection->objects = objects; _dbus_data_slot_list_init (&connection->slot_list); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 8ea653f0..8f25e076 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -593,6 +593,14 @@ set_string_field (DBusMessage *message, return append_string_field (message, field, DBUS_HEADER_FIELD_SENDER, value); + case FIELD_NAME: + return append_string_field (message, field, + DBUS_HEADER_FIELD_NAME, + value); + case FIELD_SERVICE: + return append_string_field (message, field, + DBUS_HEADER_FIELD_SERVICE, + value); default: _dbus_assert_not_reached ("appending a string field we don't support appending"); return FALSE; @@ -849,12 +857,14 @@ dbus_message_create_header (DBusMessage *message, return FALSE; } - _dbus_assert (name != NULL); - if (!append_string_field (message, - FIELD_NAME, - DBUS_HEADER_FIELD_NAME, - name)) - return FALSE; + if (name != NULL) + { + if (!append_string_field (message, + FIELD_NAME, + DBUS_HEADER_FIELD_NAME, + name)) + return FALSE; + } return TRUE; } @@ -948,6 +958,35 @@ dbus_message_new_empty_header (void) return message; } +/** + * Constructs a new message of the given message type. + * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL, + * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth. + * + * @param message_type type of message + * @returns new message or #NULL If no memory + */ +DBusMessage* +dbus_message_new (int message_type) +{ + DBusMessage *message; + + _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL); + + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!dbus_message_create_header (message, + message_type, + NULL, NULL)) + { + dbus_message_unref (message); + return NULL; + } + + return message; +} /** * Constructs a new message to invoke a method on a remote @@ -1273,6 +1312,34 @@ dbus_message_get_type (DBusMessage *message) return type; } + +/** + * Sets the message name. + * + * @param message the message + * @param name the name + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_name (DBusMessage *message, + const char *name) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + + if (name == NULL) + { + delete_string_field (message, FIELD_NAME); + return TRUE; + } + else + { + return set_string_field (message, + FIELD_NAME, + name); + } +} + /** * Gets the name of a message. * @@ -1287,6 +1354,33 @@ dbus_message_get_name (DBusMessage *message) return get_string_field (message, FIELD_NAME, NULL); } +/** + * Sets the message's destination service. + * + * @param message the message + * @param destination the destination service name + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_destination (DBusMessage *message, + const char *destination) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + + if (destination == NULL) + { + delete_string_field (message, FIELD_SERVICE); + return TRUE; + } + else + { + return set_string_field (message, + FIELD_SERVICE, + destination); + } +} + /** * Gets the destination service of a message. * diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index de5dc833..1b61c8d1 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -57,6 +57,7 @@ struct DBusMessageIter void *pad3; }; +DBusMessage* dbus_message_new (int message_type); DBusMessage* dbus_message_new_method_call (const char *name, const char *destination_service); DBusMessage* dbus_message_new_method_return (DBusMessage *method_call); @@ -70,7 +71,11 @@ 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, + const char *name); const char* dbus_message_get_name (DBusMessage *message); +dbus_bool_t dbus_message_set_destination (DBusMessage *message, + const char *destination); const char* dbus_message_get_destination (DBusMessage *message); dbus_bool_t dbus_message_set_sender (DBusMessage *message, const char *sender); diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index 55f8f749..f86a365f 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -827,7 +827,7 @@ handle_signal_and_unlock (DBusObjectRegistry *registry, object_entry = validate_id (registry, &objects[i].id); if (object_entry != NULL) { - DBusObjectVTable *vtable; + const DBusObjectVTable *vtable; DBusObjectInfo info; info_from_entry (registry, &info, object_entry); -- cgit From 5c1a8e44903bd1dedc8cbefad78b0c8b61daada5 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 12 Aug 2003 02:43:50 +0000 Subject: 2003-08-11 Havoc Pennington * bus/test.c (client_disconnect_handler): change to return HANDLED (would have been REMOVE_MESSAGE) * dbus/dbus-object.h (enum DBusHandlerResult): rename to HANDLED/NOT_YET_HANDLED instead of REMOVE_MESSAGE/ALLOW_MORE_HANDLERS to make it clearer how it should be used. --- dbus/dbus-connection.c | 10 +++++----- dbus/dbus-message-handler.c | 4 ++-- dbus/dbus-object-registry.c | 24 ++++++++++++++---------- dbus/dbus-object.h | 4 ++-- 4 files changed, 23 insertions(+), 19 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index d30ccb0a..17563f35 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2306,7 +2306,7 @@ dbus_connection_dispatch (DBusConnection *connection) message = message_link->data; - result = DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; reply_serial = dbus_message_get_reply_serial (message); reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies, @@ -2346,7 +2346,7 @@ dbus_connection_dispatch (DBusConnection *connection) result = _dbus_message_handler_handle_message (handler, connection, message); - if (result != DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS) + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) break; link = next; @@ -2363,7 +2363,7 @@ dbus_connection_dispatch (DBusConnection *connection) /* FIXME */ ; /* Did a reply we were waiting on get filtered? */ - if (reply_handler_data && result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + if (reply_handler_data && result == DBUS_HANDLER_RESULT_HANDLED) { /* Queue the timeout immediately! */ if (reply_handler_data->timeout_link) @@ -2379,7 +2379,7 @@ dbus_connection_dispatch (DBusConnection *connection) } } - if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + if (result == DBUS_HANDLER_RESULT_HANDLED) goto out; if (reply_handler_data) @@ -2405,7 +2405,7 @@ dbus_connection_dispatch (DBusConnection *connection) message); CONNECTION_LOCK (connection); - if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + if (result == DBUS_HANDLER_RESULT_HANDLED) goto out; if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) diff --git a/dbus/dbus-message-handler.c b/dbus/dbus-message-handler.c index 8bb4dd18..2e8a8b64 100644 --- a/dbus/dbus-message-handler.c +++ b/dbus/dbus-message-handler.c @@ -130,7 +130,7 @@ _dbus_message_handler_handle_message (DBusMessageHandler *handler, if (function != NULL) return (* function) (handler, connection, message, user_data); else - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /** @} */ @@ -315,7 +315,7 @@ test_handler (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index f86a365f..f1aa27de 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -705,7 +705,7 @@ handle_method_call_and_unlock (DBusObjectRegistry *registry, #endif _dbus_connection_unlock (registry->connection); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } _dbus_assert (iface_entry->n_objects > 0); @@ -729,7 +729,7 @@ handle_method_call_and_unlock (DBusObjectRegistry *registry, (* vtable->message) (&info, message); - return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; + return DBUS_HANDLER_RESULT_HANDLED; } typedef struct @@ -760,7 +760,7 @@ handle_signal_and_unlock (DBusObjectRegistry *registry, #endif _dbus_connection_unlock (registry->connection); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } _dbus_assert (signal_entry->n_connections > 0); @@ -865,7 +865,7 @@ handle_signal_and_unlock (DBusObjectRegistry *registry, #endif _dbus_connection_unlock (registry->connection); - return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; + return DBUS_HANDLER_RESULT_HANDLED; } /** @@ -902,7 +902,7 @@ _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, #endif _dbus_connection_unlock (registry->connection); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } } @@ -1202,7 +1202,8 @@ add_and_remove_objects (DBusObjectRegistry *registry) callback = dbus_callback_object_new (noop_message_function, NULL, NULL); if (callback == NULL) goto out; - + + interfaces = NULL; switch (i % 3) { case 0: @@ -1215,6 +1216,7 @@ add_and_remove_objects (DBusObjectRegistry *registry) interfaces = three_interfaces; break; } + _dbus_assert (interfaces != NULL); if (!_dbus_object_registry_add_and_unlock (registry, interfaces, @@ -1255,7 +1257,8 @@ add_and_remove_objects (DBusObjectRegistry *registry) callback = dbus_callback_object_new (noop_message_function, NULL, NULL); if (callback == NULL) goto out; - + + interfaces = NULL; switch (i % 4) { case 0: @@ -1271,6 +1274,7 @@ add_and_remove_objects (DBusObjectRegistry *registry) interfaces = three_interfaces; break; } + _dbus_assert (interfaces != NULL); if (!_dbus_object_registry_add_and_unlock (registry, interfaces, @@ -1292,7 +1296,7 @@ add_and_remove_objects (DBusObjectRegistry *registry) if (message != NULL) { if (_dbus_object_registry_handle_and_unlock (registry, message) != - DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + DBUS_HANDLER_RESULT_HANDLED) _dbus_assert_not_reached ("message not handled\n"); dbus_message_unref (message); } @@ -1301,7 +1305,7 @@ add_and_remove_objects (DBusObjectRegistry *registry) if (message != NULL) { if (_dbus_object_registry_handle_and_unlock (registry, message) != - DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + DBUS_HANDLER_RESULT_HANDLED) _dbus_assert_not_reached ("message not handled\n"); dbus_message_unref (message); } @@ -1310,7 +1314,7 @@ add_and_remove_objects (DBusObjectRegistry *registry) if (message != NULL) { if (_dbus_object_registry_handle_and_unlock (registry, message) != - DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS) + DBUS_HANDLER_RESULT_NOT_YET_HANDLED) _dbus_assert_not_reached ("message handled but no handler was registered\n"); dbus_message_unref (message); } diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h index 76d0e6f6..23c12d15 100644 --- a/dbus/dbus-object.h +++ b/dbus/dbus-object.h @@ -41,8 +41,8 @@ typedef struct DBusCallbackObject DBusCallbackObject; typedef enum { - DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */ - DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS, /**< Run any additional handlers that are interested in this message. */ + DBUS_HANDLER_RESULT_HANDLED, /**< Remove this message, no further processing. */ + DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Run any additional handlers that are interested in this message. */ DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory to handle this message. */ } DBusHandlerResult; -- cgit From 1d1b0f20a467cf1cbdcaf81fbad3a111bcff6c48 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 12 Aug 2003 04:15:49 +0000 Subject: 2003-08-12 Havoc Pennington * bus/dispatch.c (bus_dispatch): make this return proper DBusHandlerResult to avoid DBUS_ERROR_UNKNOWN_METHOD * dbus/dbus-errors.c (dbus_set_error): use _dbus_string_append_printf_valist * dbus/dbus-string.c (_dbus_string_append_printf_valist) (_dbus_string_append_printf): new * dbus/dbus-errors.h (DBUS_ERROR_UNKNOWN_MESSAGE): change to UNKNOWN_METHOD * dbus/dbus-connection.c (dbus_connection_dispatch): handle DBUS_HANDLER_RESULT_NEED_MEMORY; send default error reply if a message is unhandled. --- dbus/dbus-address.c | 1 + dbus/dbus-connection.c | 103 ++++++++++++++++++++++++++++++++++++++---- dbus/dbus-errors.c | 60 ++++++++++++++---------- dbus/dbus-errors.h | 2 +- dbus/dbus-server-debug-pipe.c | 1 + dbus/dbus-server-unix.c | 1 + dbus/dbus-server.c | 1 + dbus/dbus-string.c | 55 ++++++++++++++++++++++ dbus/dbus-string.h | 11 ++++- dbus/dbus-sysdeps.h | 3 +- 10 files changed, 200 insertions(+), 38 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-address.c b/dbus/dbus-address.c index bf9dbc3b..89dac41e 100644 --- a/dbus/dbus-address.c +++ b/dbus/dbus-address.c @@ -25,6 +25,7 @@ #include "dbus-address.h" #include "dbus-internals.h" #include "dbus-list.h" +#include "dbus-string.h" /** * @defgroup DBusAddress Address parsing diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 17563f35..ba5601e3 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -36,6 +36,7 @@ #include "dbus-protocol.h" #include "dbus-dataslot.h" #include "dbus-object-registry.h" +#include "dbus-string.h" #if 0 #define CONNECTION_LOCK(connection) do { \ @@ -1942,6 +1943,8 @@ dbus_connection_borrow_message (DBusConnection *connection) DBusDispatchStatus status; _dbus_return_val_if_fail (connection != NULL, NULL); + /* can't borrow during dispatch */ + _dbus_return_val_if_fail (!connection->dispatch_acquired, NULL); /* this is called for the side effect that it queues * up any messages from the transport @@ -1977,6 +1980,8 @@ dbus_connection_return_message (DBusConnection *connection, { _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (message != NULL); + /* can't borrow during dispatch */ + _dbus_return_if_fail (!connection->dispatch_acquired); CONNECTION_LOCK (connection); @@ -2005,6 +2010,8 @@ dbus_connection_steal_borrowed_message (DBusConnection *connection, _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (message != NULL); + /* can't borrow during dispatch */ + _dbus_return_if_fail (!connection->dispatch_acquired); CONNECTION_LOCK (connection); @@ -2074,6 +2081,22 @@ _dbus_connection_pop_message_unlocked (DBusConnection *connection) return NULL; } +static void +_dbus_connection_putback_message_link_unlocked (DBusConnection *connection, + DBusList *message_link) +{ + _dbus_assert (message_link != NULL); + /* You can't borrow a message while a link is outstanding */ + _dbus_assert (connection->message_borrowed == NULL); + + _dbus_list_prepend_link (&connection->incoming_messages, + message_link); + 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), + connection, connection->n_incoming); +} /** * Returns the first-received message from the incoming message queue, @@ -2360,7 +2383,7 @@ dbus_connection_dispatch (DBusConnection *connection) CONNECTION_LOCK (connection); if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) - /* FIXME */ ; + goto out; /* Did a reply we were waiting on get filtered? */ if (reply_handler_data && result == DBUS_HANDLER_RESULT_HANDLED) @@ -2405,22 +2428,84 @@ dbus_connection_dispatch (DBusConnection *connection) message); CONNECTION_LOCK (connection); - if (result == DBUS_HANDLER_RESULT_HANDLED) + + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) goto out; - if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) - /* FIXME */ ; + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) + { + DBusMessage *reply; + DBusString str; + DBusPreallocatedSend *preallocated; + + _dbus_verbose (" sending error %s\n", + DBUS_ERROR_UNKNOWN_METHOD); + + if (!_dbus_string_init (&str)) + { + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto out; + } + + if (!_dbus_string_append_printf (&str, + "Method \"%s\" doesn't exist\n", + dbus_message_get_name (message))) + { + _dbus_string_free (&str); + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto out; + } + + reply = dbus_message_new_error (message, + DBUS_ERROR_UNKNOWN_METHOD, + _dbus_string_get_const_data (&str)); + _dbus_string_free (&str); + + if (reply == NULL) + { + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto out; + } + + preallocated = _dbus_connection_preallocate_send_unlocked (connection); + + if (preallocated == NULL) + { + dbus_message_unref (reply); + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto out; + } + + _dbus_connection_send_preallocated_unlocked (connection, preallocated, + reply, NULL); + + dbus_message_unref (reply); + + result = DBUS_HANDLER_RESULT_HANDLED; + } _dbus_verbose (" done dispatching %p (%s) on connection %p\n", message, dbus_message_get_name (message), connection); out: + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + { + /* Put message back, and we'll start over. + * Yes this means handlers must be idempotent if they + * don't return HANDLED; c'est la vie. + */ + _dbus_connection_putback_message_link_unlocked (connection, + message_link); + } + else + { + _dbus_list_free_link (message_link); + dbus_message_unref (message); /* don't want the message to count in max message limits + * in computing dispatch status below + */ + } + _dbus_connection_release_dispatch (connection); - - _dbus_list_free_link (message_link); - dbus_message_unref (message); /* don't want the message to count in max message limits - * in computing dispatch status - */ status = _dbus_connection_get_dispatch_status_unlocked (connection); diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c index 3cf52363..82e48025 100644 --- a/dbus/dbus-errors.c +++ b/dbus/dbus-errors.c @@ -23,8 +23,8 @@ */ #include "dbus-errors.h" #include "dbus-internals.h" +#include "dbus-string.h" #include -#include #include /** @@ -292,9 +292,6 @@ dbus_error_is_set (const DBusError *error) * * @todo should be called dbus_error_set() * - * @todo stdio.h shouldn't be included in this file, - * should write _dbus_string_append_printf instead - * * @param error the error. * @param name the error name (not copied!!!) * @param format printf-style format string. @@ -306,11 +303,9 @@ dbus_set_error (DBusError *error, ...) { DBusRealError *real; + DBusString str; va_list args; - int message_length; - char *message; - char c; - + if (error == NULL) return; @@ -321,31 +316,46 @@ dbus_set_error (DBusError *error, _dbus_assert (error->name == NULL); _dbus_assert (error->message == NULL); - if (format == NULL) - format = message_from_error (name); - - va_start (args, format); - /* Measure the message length */ - message_length = vsnprintf (&c, 1, format, args) + 1; - va_end (args); + if (!_dbus_string_init (&str)) + goto nomem; - message = dbus_malloc (message_length); - - if (!message) + if (format == NULL) { - dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL); - return; + if (!_dbus_string_append (&str, + message_from_error (name))) + { + _dbus_string_free (&str); + goto nomem; + } + } + else + { + va_start (args, format); + if (!_dbus_string_append_printf_valist (&str, format, args)) + { + _dbus_string_free (&str); + goto nomem; + } + va_end (args); } - - va_start (args, format); - vsprintf (message, format, args); - va_end (args); real = (DBusRealError *)error; + + if (!_dbus_string_steal_data (&str, &real->message)) + { + _dbus_string_free (&str); + goto nomem; + } real->name = name; - real->message = message; real->const_message = FALSE; + + _dbus_string_free (&str); + + return; + + nomem: + dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL); } /** @} */ diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h index 8d8e16ec..ca398a0b 100644 --- a/dbus/dbus-errors.h +++ b/dbus/dbus-errors.h @@ -72,7 +72,7 @@ struct DBusError #define DBUS_ERROR_DISCONNECTED "org.freedesktop.DBus.Error.Disconnected" #define DBUS_ERROR_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs" #define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound" -#define DBUS_ERROR_UNKNOWN_MESSAGE "org.freedesktop.DBus.Error.UnknownMessage" +#define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod" #define DBUS_ERROR_TIMED_OUT "org.freedesktop.DBus.Error.TimedOut" void dbus_error_init (DBusError *error); diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c index 15b78608..6a66391e 100644 --- a/dbus/dbus-server-debug-pipe.c +++ b/dbus/dbus-server-debug-pipe.c @@ -27,6 +27,7 @@ #include "dbus-transport-unix.h" #include "dbus-connection-internal.h" #include "dbus-hash.h" +#include "dbus-string.h" #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index 036446af..487d60ec 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -25,6 +25,7 @@ #include "dbus-server-unix.h" #include "dbus-transport-unix.h" #include "dbus-connection-internal.h" +#include "dbus-string.h" #include #include diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index 1c9d53f0..29e20a55 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -23,6 +23,7 @@ #include "dbus-server.h" #include "dbus-server-unix.h" +#include "dbus-string.h" #ifdef DBUS_BUILD_TESTS #include "dbus-server-debug-pipe.h" #endif diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 60c25461..f4f7a2ad 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -25,6 +25,8 @@ #include "dbus-string.h" /* we allow a system header here, for speed/convenience */ #include +/* for vsnprintf */ +#include #include "dbus-marshal.h" #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 #include "dbus-string-private.h" @@ -986,6 +988,59 @@ _dbus_string_append_8_aligned (DBusString *str, return TRUE; } +/** + * Appends a printf-style formatted string + * to the #DBusString. + * + * @param str the string + * @param format printf format + * @param args variable argument list + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_append_printf_valist (DBusString *str, + const char *format, + va_list args) +{ + DBUS_STRING_PREAMBLE (str); + int len; + char c; + + /* Measure the message length without terminating nul */ + len = vsnprintf (&c, 1, format, args); + + if (!_dbus_string_lengthen (str, len)) + return FALSE; + + vsprintf (real->str + (real->len - len), + format, args); + + return TRUE; +} + +/** + * Appends a printf-style formatted string + * to the #DBusString. + * + * @param str the string + * @param format printf format + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_append_printf (DBusString *str, + const char *format, + ...) +{ + va_list args; + dbus_bool_t retval; + + va_start (args, format); + retval = _dbus_string_append_printf_valist (str, format, args); + va_end (args); + + return retval; +} + /** * Appends block of bytes with the given length to a DBusString. * diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 8fa13805..732359a0 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -28,10 +28,11 @@ #include #include +#include -DBUS_BEGIN_DECLS; +#include -typedef struct DBusString DBusString; +DBUS_BEGIN_DECLS; struct DBusString { @@ -111,6 +112,12 @@ dbus_bool_t _dbus_string_append_4_aligned (DBusString *str, const unsigned char octets[4]); dbus_bool_t _dbus_string_append_8_aligned (DBusString *str, const unsigned char octets[8]); +dbus_bool_t _dbus_string_append_printf (DBusString *str, + const char *format, + ...) _DBUS_GNUC_PRINTF (2, 3); +dbus_bool_t _dbus_string_append_printf_valist (DBusString *str, + const char *format, + va_list args); void _dbus_string_delete (DBusString *str, int start, int len); diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index cfe0cd25..bfdcfb0a 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -25,7 +25,6 @@ #ifndef DBUS_SYSDEPS_H #define DBUS_SYSDEPS_H -#include #include /* this is perhaps bogus, but strcmp() etc. are faster if we use the @@ -47,6 +46,8 @@ DBUS_BEGIN_DECLS; * dbus-memory.c) */ +typedef struct DBusString DBusString; + #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) #define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) \ __attribute__((__format__ (__printf__, format_idx, arg_idx))) -- cgit From a6c8a71b1bcba04b63812a61f668e87af0922e5e Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 14 Aug 2003 22:49:13 +0000 Subject: 2003-08-14 Havoc Pennington * dbus/dbus-pending-call.c: start on new object that will replace DBusMessageHandler and ReplyHandlerData for tracking outstanding replies * dbus/dbus-gproxy.c: start on proxy object used to communicate with remote interfaces * dbus/dbus-gidl.c: do the boring boilerplate in here --- dbus/dbus-pending-call.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-pending-call.h | 55 ++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 dbus/dbus-pending-call.c create mode 100644 dbus/dbus-pending-call.h (limited to 'dbus') diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c new file mode 100644 index 00000000..7a65ad62 --- /dev/null +++ b/dbus/dbus-pending-call.c @@ -0,0 +1,225 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-pending-call.c Object representing a call in progress. + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-message-pending.h" +#include "dbus-list.h" +#include "dbus-threads.h" +#include "dbus-test.h" +#include "dbus-connection-internal.h" + +/** + * @defgroup DBusPendingCallInternals DBusPendingCall implementation details + * @ingroup DBusInternals + * @brief DBusPendingCall private implementation details. + * + * The guts of DBusPendingCall and its methods. + * + * @{ + */ + +/** + * @brief Internals of DBusPendingCall + * + * Object representing a reply message that we're waiting for. + */ +struct DBusPendingCall +{ + DBusAtomic refcount; /**< reference count */ + + DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ + void *user_data; /**< user data for function */ + DBusFreeFunction free_user_data; /**< free the user data */ + + DBusConnection *connection; /**< Connections we're associated with */ + DBusMessage *reply; /**< Reply (after we've received it) */ + DBusTimeout *timeout; /**< Timeout */ + + DBusList *timeout_link; /**< Preallocated timeout response */ + + dbus_uint32_t reply_serial; /**< Expected serial of reply */ + + unsigned int completed : 1; /**< TRUE if completed */ + unsigned int timeout_added : 1; /**< Have added the timeout */ +}; + +/** + * Creates a new pending reply object. + * + * @param connection connection where reply will arrive + * @param reply_serial reply serial of the expected reply + * @returns a new #DBusPendingCall or #NULL if no memory. + */ +DBusPendingCall* +_dbus_pending_call_new (DBusConnection *connection, + dbus_uint32_t reply_serial) +{ + DBusPendingCall *pending; + + pending = dbus_new (DBusPendingCall, 1); + + if (pending == NULL) + return NULL; + + pending->refcount.value = 1; + pending->connection = connection; + pending->reply_serial = reply_serial; + + return pending; +} + +/** @} */ + +/** + * @defgroup DBusPendingCall DBusPendingCall + * @ingroup DBus + * @brief Pending reply to a method call message + * + * A DBusPendingCall is an object representing an + * expected reply. A #DBusPendingCall can be created + * when you send a message that should have a reply. + * + * @{ + */ + +/** + * @typedef DBusPendingCall + * + * Opaque data type representing a message pending. + */ + +/** + * Increments the reference count on a pending call. + * + * @param pending the pending call object + */ +void +dbus_pending_call_ref (DBusPendingCall *pending) +{ + _dbus_return_if_fail (pending != NULL); + + _dbus_atomic_inc (&pending->refcount); +} + +/** + * Decrements the reference count on a pending call, + * freeing it if the count reaches 0. + * + * @param pending the pending call object + */ +void +dbus_pending_call_unref (DBusPendingCall *pending) +{ + dbus_bool_t last_unref; + + _dbus_return_if_fail (pending != NULL); + + last_unref = (_dbus_atomic_dec (&pending->refcount) == 1); + + if (last_unref) + { + if (pending->free_user_data) + (* pending->free_user_data) (pending->user_data); + + + if (pending->connection != NULL) + { + _dbus_connection_pending_destroyed_locked (connection, pending); + pending->connection = NULL; + } + + if (pending->reply) + { + dbus_message_unref (pending->reply); + pending->reply = NULL; + } + + dbus_free (pending); + } +} + +/** + * Sets a notification function to be called when the reply is + * received or the pending call times out. + * + * @param pending the pending call + * @param function notifier function + * @param user_data data to pass to notifier function + * @param free_user_data function to free the user data + * + */ +void +dbus_pending_call_set_notify (DBusPendingCall *pending, + DBusPendingCallNotifyFunction function, + void *user_data, + DBusFreeFunction free_user_data) +{ + DBusFreeFunction old_free_func; + void *old_user_data; + + _dbus_return_if_fail (pending != NULL); + + _DBUS_LOCK (pending_call); + old_free_func = pending->free_user_data; + old_user_data = pending->user_data; + + pending->user_data = user_data; + pending->free_user_data = free_user_data; + pending->function = function; + _DBUS_UNLOCK (pending_call); + + if (old_free_func) + (* old_free_func) (old_user_data); +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +static DBusPendingResult +test_pending (DBusPendingCall *pending, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + return DBUS_PENDING_RESULT_NOT_YET_HANDLED; +} + +static void +free_test_data (void *data) +{ + /* does nothing */ +} + +/** + * @ingroup DBusPendingCallInternals + * Unit test for DBusPendingCall. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_pending_call_test (const char *test_data_dir) +{ + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h new file mode 100644 index 00000000..ff2c176a --- /dev/null +++ b/dbus/dbus-pending-call.h @@ -0,0 +1,55 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-pending-call.h Object representing a call in progress. + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_PENDING_CALL_H +#define DBUS_PENDING_CALL_H + +#include +#include +#include + +DBUS_BEGIN_DECLS; + +typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, + void *user_data); + +DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, + dbus_uint32_t reply_serial); + +void dbus_pending_call_ref (DBusPendingCall *pending); +void dbus_pending_call_unref (DBusPendingCall *pending); +void dbus_pending_call_set_notify (DBusPendingCall *pending, + DBusPendingCallNotifyFunction function, + void *user_data, + DBusFreeFunction free_user_data); +dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending); +DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending); + + + +DBUS_END_DECLS; + +#endif /* DBUS_PENDING_CALL_H */ -- cgit From ef614207fc4f03e5cc02faeb109f739eb1ccdf31 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 15 Aug 2003 04:17:58 +0000 Subject: 2003-08-15 Havoc Pennington * dbus/dbus-connection.c, dbus/dbus-pending-call.c: Finish the pending call stuff --- dbus/Makefile.am | 2 + dbus/dbus-connection-internal.h | 45 +++++ dbus/dbus-connection.c | 364 ++++++++++++++++++++++------------------ dbus/dbus-connection.h | 6 +- dbus/dbus-pending-call.c | 146 ++++++++++------ dbus/dbus-pending-call.h | 9 +- dbus/dbus-test.c | 6 + dbus/dbus-test.h | 2 +- dbus/dbus.h | 1 + 9 files changed, 358 insertions(+), 223 deletions(-) (limited to 'dbus') diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 8c919f31..3537b935 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -19,6 +19,7 @@ dbusinclude_HEADERS= \ dbus-message-handler.h \ dbus-object.h \ dbus-objectid.h \ + dbus-pending-call.h \ dbus-protocol.h \ dbus-server.h \ dbus-threads.h \ @@ -48,6 +49,7 @@ DBUS_LIB_SOURCES= \ dbus-objectid.c \ dbus-object-registry.c \ dbus-object-registry.h \ + dbus-pending-call.c \ dbus-resources.c \ dbus-resources.h \ dbus-server.c \ diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 423df5f8..d9d5c5b4 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -29,6 +29,7 @@ #include #include #include +#include DBUS_BEGIN_DECLS; @@ -39,6 +40,9 @@ typedef enum DBUS_ITERATION_BLOCK = 1 << 2 /**< Block if nothing to do. */ } DBusIterationFlags; +/** default timeout value when waiting for a message reply */ +#define _DBUS_DEFAULT_TIMEOUT_VALUE (15 * 1000) + void _dbus_connection_lock (DBusConnection *connection); void _dbus_connection_unlock (DBusConnection *connection); void _dbus_connection_ref_unlocked (DBusConnection *connection); @@ -85,6 +89,47 @@ DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandl void _dbus_connection_init_id (DBusConnection *connection, DBusObjectID *id); +DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, + int timeout_milliseconds, + DBusTimeoutHandler timeout_handler); + +void _dbus_pending_call_notify (DBusPendingCall *pending); + +void _dbus_connection_remove_pending_call (DBusConnection *connection, + DBusPendingCall *pending); + +/** + * @addtogroup DBusPendingCallInternals DBusPendingCall implementation details + * @{ + */ +/** + * @brief Internals of DBusPendingCall + * + * Object representing a reply message that we're waiting for. + */ +struct DBusPendingCall +{ + DBusAtomic refcount; /**< reference count */ + + DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ + void *user_data; /**< user data for function */ + DBusFreeFunction free_user_data; /**< free the user data */ + + DBusConnection *connection; /**< Connections we're associated with */ + DBusMessage *reply; /**< Reply (after we've received it) */ + DBusTimeout *timeout; /**< Timeout */ + + DBusList *timeout_link; /**< Preallocated timeout response */ + + dbus_uint32_t reply_serial; /**< Expected serial of reply */ + + unsigned int completed : 1; /**< TRUE if completed */ + unsigned int timeout_added : 1; /**< Have added the timeout */ +}; + +/** @} End of DBusPendingCallInternals */ + + DBUS_END_DECLS; #endif /* DBUS_CONNECTION_INTERNAL_H */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ba5601e3..3af00ed0 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -37,6 +37,7 @@ #include "dbus-dataslot.h" #include "dbus-object-registry.h" #include "dbus-string.h" +#include "dbus-pending-call.h" #if 0 #define CONNECTION_LOCK(connection) do { \ @@ -124,9 +125,6 @@ * @{ */ -/** default timeout value when waiting for a message reply */ -#define DEFAULT_TIMEOUT_VALUE (15 * 1000) - static dbus_bool_t _dbus_modify_sigpipe = TRUE; /** @@ -163,7 +161,7 @@ struct DBusConnection DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ - DBusHashTable *pending_replies; /**< Hash of message serials and their message handlers. */ + DBusHashTable *pending_replies; /**< Hash of message serials to #DBusPendingCall. */ dbus_uint32_t client_serial; /**< Client serial. Increments each time a message is sent */ DBusList *disconnect_message_link; /**< Preallocated list node for queueing the disconnection message */ @@ -184,21 +182,6 @@ struct DBusConnection DBusObjectRegistry *objects; /**< Objects registered with this connection */ }; -typedef struct -{ - DBusConnection *connection; - DBusMessageHandler *handler; - DBusTimeout *timeout; - int serial; - - DBusList *timeout_link; /* Preallocated timeout response */ - - dbus_bool_t timeout_added; - dbus_bool_t connection_added; -} ReplyHandlerData; - -static void reply_handler_data_free (ReplyHandlerData *data); - static void _dbus_connection_remove_timeout_locked (DBusConnection *connection, DBusTimeout *timeout); static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection); @@ -283,7 +266,7 @@ void _dbus_connection_queue_received_message_link (DBusConnection *connection, DBusList *link) { - ReplyHandlerData *reply_handler_data; + DBusPendingCall *pending; dbus_int32_t reply_serial; DBusMessage *message; @@ -297,14 +280,15 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection, reply_serial = dbus_message_get_reply_serial (message); if (reply_serial != -1) { - reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies, - reply_serial); - if (reply_handler_data != NULL) + pending = _dbus_hash_table_lookup_int (connection->pending_replies, + reply_serial); + if (pending != NULL) { - if (reply_handler_data->timeout_added) + if (pending->timeout_added) _dbus_connection_remove_timeout_locked (connection, - reply_handler_data->timeout); - reply_handler_data->timeout_added = FALSE; + pending->timeout); + + pending->timeout_added = FALSE; } } @@ -555,6 +539,86 @@ _dbus_connection_notify_disconnected (DBusConnection *connection) } } +static dbus_bool_t +_dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, + DBusPendingCall *pending) +{ + _dbus_assert (pending->reply_serial != 0); + + if (!_dbus_connection_add_timeout (connection, pending->timeout)) + return FALSE; + + if (!_dbus_hash_table_insert_int (connection->pending_replies, + pending->reply_serial, + pending)) + { + _dbus_connection_remove_timeout (connection, pending->timeout); + return FALSE; + } + + pending->timeout_added = TRUE; + pending->connection = connection; + + dbus_pending_call_ref (pending); + + return TRUE; +} + +static void +free_pending_call_on_hash_removal (void *data) +{ + DBusPendingCall *pending; + + if (data == NULL) + return; + + pending = data; + + if (pending->connection) + { + if (pending->timeout_added) + { + _dbus_connection_remove_timeout (pending->connection, + pending->timeout); + pending->timeout_added = FALSE; + } + + pending->connection = NULL; + + dbus_pending_call_unref (pending); + } +} + +static void +_dbus_connection_detach_pending_call_and_unlock (DBusConnection *connection, + DBusPendingCall *pending) +{ + /* The idea here is to avoid finalizing the pending call + * with the lock held, since there's a destroy notifier + * in pending call that goes out to application code. + */ + dbus_pending_call_ref (pending); + _dbus_hash_table_remove_int (connection->pending_replies, + pending->reply_serial); + CONNECTION_UNLOCK (connection); + dbus_pending_call_unref (pending); +} + +/** + * Removes a pending call from the connection, such that + * the pending reply will be ignored. May drop the last + * reference to the pending call. + * + * @param connection the connection + * @param pending the pending call + */ +void +_dbus_connection_remove_pending_call (DBusConnection *connection, + DBusPendingCall *pending) +{ + CONNECTION_LOCK (connection); + _dbus_connection_detach_pending_call_and_unlock (connection, pending); +} /** * Acquire the transporter I/O path. This must be done before @@ -699,7 +763,8 @@ _dbus_connection_new_for_transport (DBusTransport *transport) pending_replies = _dbus_hash_table_new (DBUS_HASH_INT, - NULL, (DBusFreeFunction)reply_handler_data_free); + NULL, + (DBusFreeFunction)free_pending_call_on_hash_removal); if (pending_replies == NULL) goto error; @@ -1442,6 +1507,28 @@ dbus_connection_send_preallocated (DBusConnection *connection, CONNECTION_UNLOCK (connection); } +static dbus_bool_t +_dbus_connection_send_unlocked (DBusConnection *connection, + DBusMessage *message, + dbus_uint32_t *client_serial) +{ + DBusPreallocatedSend *preallocated; + + _dbus_assert (connection != NULL); + _dbus_assert (message != NULL); + + preallocated = _dbus_connection_preallocate_send_unlocked (connection); + if (preallocated == NULL) + return FALSE; + + + _dbus_connection_send_preallocated_unlocked (connection, + preallocated, + message, + client_serial); + return TRUE; +} + /** * Adds a message to the outgoing message queue. Does not block to * write the message to the network; that happens asynchronously. To @@ -1465,50 +1552,41 @@ dbus_connection_send (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *client_serial) { - DBusPreallocatedSend *preallocated; - _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (message != NULL, FALSE); CONNECTION_LOCK (connection); - - preallocated = _dbus_connection_preallocate_send_unlocked (connection); - if (preallocated == NULL) + + if (!_dbus_connection_send_unlocked (connection, message, client_serial)) { CONNECTION_UNLOCK (connection); return FALSE; } - else - { - _dbus_connection_send_preallocated_unlocked (connection, - preallocated, - message, - client_serial); - CONNECTION_UNLOCK (connection); - return TRUE; - } + + CONNECTION_UNLOCK (connection); + return TRUE; } static dbus_bool_t reply_handler_timeout (void *data) { DBusConnection *connection; - ReplyHandlerData *reply_handler_data = data; DBusDispatchStatus status; + DBusPendingCall *pending = data; - connection = reply_handler_data->connection; + connection = pending->connection; CONNECTION_LOCK (connection); - if (reply_handler_data->timeout_link) + if (pending->timeout_link) { _dbus_connection_queue_synthesized_message_link (connection, - reply_handler_data->timeout_link); - reply_handler_data->timeout_link = NULL; + pending->timeout_link); + pending->timeout_link = NULL; } _dbus_connection_remove_timeout (connection, - reply_handler_data->timeout); - reply_handler_data->timeout_added = FALSE; + pending->timeout); + pending->timeout_added = FALSE; status = _dbus_connection_get_dispatch_status_unlocked (connection); @@ -1518,52 +1596,29 @@ reply_handler_timeout (void *data) return TRUE; } -static void -reply_handler_data_free (ReplyHandlerData *data) -{ - if (!data) - return; - - if (data->timeout_added) - _dbus_connection_remove_timeout_locked (data->connection, - data->timeout); - - if (data->connection_added) - _dbus_message_handler_remove_connection (data->handler, - data->connection); - - if (data->timeout_link) - { - dbus_message_unref ((DBusMessage *)data->timeout_link->data); - _dbus_list_free_link (data->timeout_link); - } - - dbus_message_handler_unref (data->handler); - - dbus_free (data); -} - /** * Queues a message to send, as with dbus_connection_send_message(), - * but also sets up a DBusMessageHandler to receive a reply to the + * but also returns a #DBusPendingCall used to receive a reply to the * message. If no reply is received in the given timeout_milliseconds, - * expires the pending reply and sends the DBusMessageHandler a - * synthetic error reply (generated in-process, not by the remote - * application) indicating that a timeout occurred. - * - * Reply handlers see their replies after message filters see them, - * but before message handlers added with - * dbus_connection_register_handler() see them, regardless of the - * reply message's name. Reply handlers are only handed a single - * message as a reply, after one reply has been seen the handler is - * removed. If a filter filters out the reply before the handler sees - * it, the reply is immediately timed out and a timeout error reply is + * this function expires the pending reply and generates a synthetic + * error reply (generated in-process, not by the remote application) + * indicating that a timeout occurred. + * + * A #DBusPendingCall will see a reply message after any filters, but + * before any object instances or other handlers. A #DBusPendingCall + * will always see exactly one reply message, unless it's cancelled + * with dbus_pending_call_cancel(). + * + * If a filter filters out the reply before the handler sees it, the + * reply is immediately timed out and a timeout error reply is * generated. If a filter removes the timeout error reply then the - * reply handler will never be called. Filters should not do this. + * #DBusPendingCall will get confused. Filtering the timeout error + * is thus considered a bug and will print a warning. * - * If #NULL is passed for the reply_handler, the timeout reply will - * still be generated and placed into the message queue, but no - * specific message handler will receive the reply. + * If #NULL is passed for the pending_return, the #DBusPendingCall + * will still be generated internally, and used to track + * the message reply timeout. This means a timeout error will + * occur if no reply arrives, unlike with dbus_connection_send(). * * If -1 is passed for the timeout, a sane default timeout is used. -1 * is typically the best value for the timeout for this reason, unless @@ -1573,7 +1628,7 @@ reply_handler_data_free (ReplyHandlerData *data) * * @param connection the connection * @param message the message to send - * @param reply_handler message handler expecting the reply, or #NULL + * @param pending_return return location for a #DBusPendingCall object, or #NULL * @param timeout_milliseconds timeout in milliseconds or -1 for default * @returns #TRUE if the message is successfully queued, #FALSE if no memory. * @@ -1581,63 +1636,30 @@ reply_handler_data_free (ReplyHandlerData *data) dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection, DBusMessage *message, - DBusMessageHandler *reply_handler, + DBusPendingCall **pending_return, int timeout_milliseconds) { - DBusTimeout *timeout; - ReplyHandlerData *data; + DBusPendingCall *pending; DBusMessage *reply; DBusList *reply_link; dbus_int32_t serial = -1; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (message != NULL, FALSE); - _dbus_return_val_if_fail (reply_handler != NULL, FALSE); _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); - - if (timeout_milliseconds == -1) - timeout_milliseconds = DEFAULT_TIMEOUT_VALUE; - data = dbus_new0 (ReplyHandlerData, 1); - - if (!data) - return FALSE; + if (pending_return) + *pending_return = NULL; - timeout = _dbus_timeout_new (timeout_milliseconds, reply_handler_timeout, - data, NULL); + pending = _dbus_pending_call_new (connection, + timeout_milliseconds, + reply_handler_timeout); - if (!timeout) - { - reply_handler_data_free (data); - return FALSE; - } + if (pending == NULL) + return FALSE; CONNECTION_LOCK (connection); - /* Add timeout */ - if (!_dbus_connection_add_timeout (connection, timeout)) - { - reply_handler_data_free (data); - _dbus_timeout_unref (timeout); - CONNECTION_UNLOCK (connection); - return FALSE; - } - - /* The connection now owns the reference to the timeout. */ - _dbus_timeout_unref (timeout); - - data->timeout_added = TRUE; - data->timeout = timeout; - data->connection = connection; - - if (!_dbus_message_handler_add_connection (reply_handler, connection)) - { - CONNECTION_UNLOCK (connection); - reply_handler_data_free (data); - return FALSE; - } - data->connection_added = TRUE; - /* Assign a serial to the message */ if (dbus_message_get_serial (message) == 0) { @@ -1645,17 +1667,14 @@ dbus_connection_send_with_reply (DBusConnection *connection, _dbus_message_set_serial (message, serial); } - data->handler = reply_handler; - data->serial = serial; - - dbus_message_handler_ref (reply_handler); + pending->reply_serial = serial; reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, "No reply within specified time"); if (!reply) { CONNECTION_UNLOCK (connection); - reply_handler_data_free (data); + dbus_pending_call_unref (pending); return FALSE; } @@ -1664,33 +1683,42 @@ dbus_connection_send_with_reply (DBusConnection *connection, { CONNECTION_UNLOCK (connection); dbus_message_unref (reply); - reply_handler_data_free (data); + dbus_pending_call_unref (pending); return FALSE; } - data->timeout_link = reply_link; - - /* Insert the serial in the pending replies hash. */ - if (!_dbus_hash_table_insert_int (connection->pending_replies, serial, data)) + pending->timeout_link = reply_link; + + /* Insert the serial in the pending replies hash; + * hash takes a refcount on DBusPendingCall. + * Also, add the timeout. + */ + if (!_dbus_connection_attach_pending_call_unlocked (connection, + pending)) { CONNECTION_UNLOCK (connection); - reply_handler_data_free (data); + dbus_pending_call_unref (pending); return FALSE; } - - CONNECTION_UNLOCK (connection); - if (!dbus_connection_send (connection, message, NULL)) + if (!_dbus_connection_send_unlocked (connection, message, NULL)) { - /* This will free the handler data too */ - _dbus_hash_table_remove_int (connection->pending_replies, serial); + _dbus_connection_detach_pending_call_and_unlock (connection, + pending); return FALSE; } + if (pending_return) + { + dbus_pending_call_ref (pending); + *pending_return = pending; + } + + CONNECTION_UNLOCK (connection); + return TRUE; } - static DBusMessage* check_for_reply_unlocked (DBusConnection *connection, dbus_uint32_t client_serial) @@ -1755,7 +1783,7 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, _dbus_return_val_if_error_is_set (error, NULL); if (timeout_milliseconds == -1) - timeout_milliseconds = DEFAULT_TIMEOUT_VALUE; + timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; /* it would probably seem logical to pass in _DBUS_INT_MAX * for infinite timeout, but then math below would get @@ -2283,7 +2311,7 @@ dbus_connection_dispatch (DBusConnection *connection) DBusMessage *message; DBusList *link, *filter_list_copy, *message_link; DBusHandlerResult result; - ReplyHandlerData *reply_handler_data; + DBusPendingCall *pending; dbus_int32_t reply_serial; DBusDispatchStatus status; @@ -2332,8 +2360,8 @@ dbus_connection_dispatch (DBusConnection *connection) result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; reply_serial = dbus_message_get_reply_serial (message); - reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies, - reply_serial); + pending = _dbus_hash_table_lookup_int (connection->pending_replies, + reply_serial); if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy)) { @@ -2386,34 +2414,42 @@ dbus_connection_dispatch (DBusConnection *connection) goto out; /* Did a reply we were waiting on get filtered? */ - if (reply_handler_data && result == DBUS_HANDLER_RESULT_HANDLED) + if (pending && result == DBUS_HANDLER_RESULT_HANDLED) { /* Queue the timeout immediately! */ - if (reply_handler_data->timeout_link) + if (pending->timeout_link) { _dbus_connection_queue_synthesized_message_link (connection, - reply_handler_data->timeout_link); - reply_handler_data->timeout_link = NULL; + pending->timeout_link); + pending->timeout_link = NULL; } else { /* We already queued the timeout? Then it was filtered! */ - _dbus_warn ("The timeout error with reply serial %d was filtered, so the reply handler will never be called.\n", reply_serial); + _dbus_warn ("The timeout error with reply serial %d was filtered, so the DBusPendingCall will never stop pending.\n", reply_serial); } } if (result == DBUS_HANDLER_RESULT_HANDLED) goto out; - if (reply_handler_data) + if (pending) { - CONNECTION_UNLOCK (connection); + _dbus_verbose (" handing message %p to pending call\n", message); + + _dbus_assert (pending->reply == NULL); + pending->reply = message; + dbus_message_ref (pending->reply); + + dbus_pending_call_ref (pending); /* in case there's no app with a ref held */ + _dbus_connection_detach_pending_call_and_unlock (connection, pending); + + /* Must be called unlocked since it invokes app callback */ + _dbus_pending_call_notify (pending); + dbus_pending_call_unref (pending); - _dbus_verbose (" running reply handler on message %p\n", message); + pending = NULL; - result = _dbus_message_handler_handle_message (reply_handler_data->handler, - connection, message); - reply_handler_data_free (reply_handler_data); CONNECTION_LOCK (connection); goto out; } diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 7bf1221a..ef106524 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -37,6 +37,7 @@ typedef struct DBusWatch DBusWatch; typedef struct DBusTimeout DBusTimeout; typedef struct DBusMessageHandler DBusMessageHandler; typedef struct DBusPreallocatedSend DBusPreallocatedSend; +typedef struct DBusPendingCall DBusPendingCall; typedef enum { @@ -76,6 +77,9 @@ typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection, unsigned long uid, void *data); +typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, + void *user_data); + DBusConnection* dbus_connection_open (const char *address, DBusError *error); void dbus_connection_ref (DBusConnection *connection); @@ -97,7 +101,7 @@ dbus_bool_t dbus_connection_send (DBusConnection dbus_uint32_t *client_serial); dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection, DBusMessage *message, - DBusMessageHandler *reply_handler, + DBusPendingCall **pending_return, int timeout_milliseconds); DBusMessage * dbus_connection_send_with_reply_and_block (DBusConnection *connection, DBusMessage *message, diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c index 7a65ad62..84ca7ae0 100644 --- a/dbus/dbus-pending-call.c +++ b/dbus/dbus-pending-call.c @@ -22,11 +22,11 @@ */ #include "dbus-internals.h" -#include "dbus-message-pending.h" +#include "dbus-connection-internal.h" +#include "dbus-pending-call.h" #include "dbus-list.h" #include "dbus-threads.h" #include "dbus-test.h" -#include "dbus-connection-internal.h" /** * @defgroup DBusPendingCallInternals DBusPendingCall implementation details @@ -38,56 +38,65 @@ * @{ */ -/** - * @brief Internals of DBusPendingCall - * - * Object representing a reply message that we're waiting for. - */ -struct DBusPendingCall -{ - DBusAtomic refcount; /**< reference count */ - - DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ - void *user_data; /**< user data for function */ - DBusFreeFunction free_user_data; /**< free the user data */ - - DBusConnection *connection; /**< Connections we're associated with */ - DBusMessage *reply; /**< Reply (after we've received it) */ - DBusTimeout *timeout; /**< Timeout */ - - DBusList *timeout_link; /**< Preallocated timeout response */ - - dbus_uint32_t reply_serial; /**< Expected serial of reply */ - - unsigned int completed : 1; /**< TRUE if completed */ - unsigned int timeout_added : 1; /**< Have added the timeout */ -}; - /** * Creates a new pending reply object. * * @param connection connection where reply will arrive - * @param reply_serial reply serial of the expected reply + * @param timeout_milliseconds length of timeout, -1 for default + * @param timeout_handler timeout handler, takes pending call as data * @returns a new #DBusPendingCall or #NULL if no memory. */ DBusPendingCall* -_dbus_pending_call_new (DBusConnection *connection, - dbus_uint32_t reply_serial) +_dbus_pending_call_new (DBusConnection *connection, + int timeout_milliseconds, + DBusTimeoutHandler timeout_handler) { DBusPendingCall *pending; + DBusTimeout *timeout; + _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); + + if (timeout_milliseconds == -1) + timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; + pending = dbus_new (DBusPendingCall, 1); if (pending == NULL) return NULL; + timeout = _dbus_timeout_new (timeout_milliseconds, + timeout_handler, + pending, NULL); + + if (timeout == NULL) + { + dbus_free (pending); + return NULL; + } + pending->refcount.value = 1; pending->connection = connection; - pending->reply_serial = reply_serial; - + pending->timeout = timeout; + return pending; } +/** + * Calls notifier function for the pending call + * and sets the call to completed. + * + * @param pending the pending call + * + */ +void +_dbus_pending_call_notify (DBusPendingCall *pending) +{ + pending->completed = TRUE; + + if (pending->function) + (* pending->function) (pending, pending->user_data); +} + /** @} */ /** @@ -138,14 +147,24 @@ dbus_pending_call_unref (DBusPendingCall *pending) if (last_unref) { + /* If we get here, we should be already detached + * from the connection, or never attached. + */ + _dbus_assert (pending->connection == NULL); + _dbus_assert (!pending->timeout_added); + + /* this assumes we aren't holding connection lock... */ if (pending->free_user_data) (* pending->free_user_data) (pending->user_data); - - if (pending->connection != NULL) + if (pending->timeout != NULL) + _dbus_timeout_unref (pending->timeout); + + if (pending->timeout_link) { - _dbus_connection_pending_destroyed_locked (connection, pending); - pending->connection = NULL; + dbus_message_unref ((DBusMessage *)pending->timeout_link->data); + _dbus_list_free_link (pending->timeout_link); + pending->timeout_link = NULL; } if (pending->reply) @@ -179,37 +198,66 @@ dbus_pending_call_set_notify (DBusPendingCall *pending, _dbus_return_if_fail (pending != NULL); - _DBUS_LOCK (pending_call); old_free_func = pending->free_user_data; old_user_data = pending->user_data; pending->user_data = user_data; pending->free_user_data = free_user_data; pending->function = function; - _DBUS_UNLOCK (pending_call); if (old_free_func) (* old_free_func) (old_user_data); } -/** @} */ +/** + * Cancels the pending call, such that any reply + * or error received will just be ignored. + * Drops at least one reference to the #DBusPendingCall + * so will free the call if nobody else is holding + * a reference. + * + * @param pending the pending call + */ +void +dbus_pending_call_cancel (DBusPendingCall *pending) +{ + if (pending->connection) + _dbus_connection_remove_pending_call (pending->connection, + pending); +} -#ifdef DBUS_BUILD_TESTS -static DBusPendingResult -test_pending (DBusPendingCall *pending, - DBusConnection *connection, - DBusMessage *message, - void *user_data) +/** + * Checks whether the pending call has received a reply + * yet, or not. + * + * @param pending the pending call + * @returns #TRUE if a reply has been received + */ +dbus_bool_t +dbus_pending_call_get_completed (DBusPendingCall *pending) { - return DBUS_PENDING_RESULT_NOT_YET_HANDLED; + return pending->completed; } -static void -free_test_data (void *data) +/** + * Gets the reply, or returns #NULL if none has been received yet. The + * reference count is not incremented on the returned message, so you + * have to keep a reference count on the pending call (or add one + * to the message). + * + * @param pending the pending call + * @returns the reply message or #NULL. + */ +DBusMessage* +dbus_pending_call_get_reply (DBusPendingCall *pending) { - /* does nothing */ + return pending->reply; } +/** @} */ + +#ifdef DBUS_BUILD_TESTS + /** * @ingroup DBusPendingCallInternals * Unit test for DBusPendingCall. diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h index ff2c176a..66f1bac5 100644 --- a/dbus/dbus-pending-call.h +++ b/dbus/dbus-pending-call.h @@ -33,23 +33,16 @@ DBUS_BEGIN_DECLS; -typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, - void *user_data); - -DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, - dbus_uint32_t reply_serial); - void dbus_pending_call_ref (DBusPendingCall *pending); void dbus_pending_call_unref (DBusPendingCall *pending); void dbus_pending_call_set_notify (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, void *user_data, DBusFreeFunction free_user_data); +void dbus_pending_call_cancel (DBusPendingCall *pending); dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending); DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending); - - DBUS_END_DECLS; #endif /* DBUS_PENDING_CALL_H */ diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index c3b31107..8a99d179 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -197,6 +197,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) die ("auth"); check_memleaks (); + + printf ("%s: running pending call tests\n", "dbus-test"); + if (!_dbus_pending_call_test (test_data_dir)) + die ("auth"); + + check_memleaks (); printf ("%s: completed successfully\n", "dbus-test"); #else diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index 8537be40..276e8f9e 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -56,7 +56,7 @@ dbus_bool_t _dbus_memory_test (void); dbus_bool_t _dbus_object_test (void); dbus_bool_t _dbus_object_id_test (void); dbus_bool_t _dbus_object_registry_test (void); - +dbus_bool_t _dbus_pending_call_test (const char *test_data_dir); void dbus_internal_do_not_use_run_tests (const char *test_data_dir); dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename, diff --git a/dbus/dbus.h b/dbus/dbus.h index d83a4a50..12a087f5 100644 --- a/dbus/dbus.h +++ b/dbus/dbus.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include -- cgit From a1b0bd33408f03894987ac32b4e6b46c6a15a594 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 15 Aug 2003 23:10:12 +0000 Subject: 2003-08-15 Havoc Pennington * dbus/dbus-pending-call.c (dbus_pending_call_block): implement * dbus/dbus-connection.c (dbus_connection_send_with_reply_and_block): factor out internals; change to convert any error replies to DBusError instead of returning them as a message --- dbus/dbus-connection-internal.h | 9 ++- dbus/dbus-connection.c | 161 ++++++++++++++++++++++++++++------------ dbus/dbus-pending-call.c | 25 +++++++ dbus/dbus-pending-call.h | 1 + 4 files changed, 147 insertions(+), 49 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index d9d5c5b4..f26c92e6 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -88,15 +88,18 @@ DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandl DBusMessage *message); void _dbus_connection_init_id (DBusConnection *connection, DBusObjectID *id); - DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, int timeout_milliseconds, DBusTimeoutHandler timeout_handler); - void _dbus_pending_call_notify (DBusPendingCall *pending); - void _dbus_connection_remove_pending_call (DBusConnection *connection, DBusPendingCall *pending); +DBusMessage* _dbus_connection_block_for_reply (DBusConnection *connection, + dbus_uint32_t client_serial, + int timeout_milliseconds); +void _dbus_pending_call_complete_and_unlock (DBusPendingCall *pending, + DBusMessage *message); + /** * @addtogroup DBusPendingCallInternals DBusPendingCall implementation details diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 3af00ed0..bc26a3ec 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -620,6 +620,38 @@ _dbus_connection_remove_pending_call (DBusConnection *connection, _dbus_connection_detach_pending_call_and_unlock (connection, pending); } +/** + * Completes a pending call with the given message, + * or if the message is #NULL, by timing out the pending call. + * + * @param pending the pending call + * @param message the message to complete the call with, or #NULL + * to time out the call + */ +void +_dbus_pending_call_complete_and_unlock (DBusPendingCall *pending, + DBusMessage *message) +{ + if (message == NULL) + { + message = pending->timeout_link->data; + _dbus_list_clear (&pending->timeout_link); + } + + _dbus_verbose (" handing message %p to pending call\n", message); + + _dbus_assert (pending->reply == NULL); + pending->reply = message; + dbus_message_ref (pending->reply); + + dbus_pending_call_ref (pending); /* in case there's no app with a ref held */ + _dbus_connection_detach_pending_call_and_unlock (pending->connection, pending); + + /* Must be called unlocked since it invokes app callback */ + _dbus_pending_call_notify (pending); + dbus_pending_call_unref (pending); +} + /** * Acquire the transporter I/O path. This must be done before * doing any I/O in the transporter. May sleep and drop the @@ -1745,42 +1777,31 @@ check_for_reply_unlocked (DBusConnection *connection, } /** - * Sends a message and blocks a certain time period while waiting for a reply. - * This function does not dispatch any message handlers until the main loop - * has been reached. This function is used to do non-reentrant "method calls." - * If a reply is received, it is returned, and removed from the incoming - * message queue. If it is not received, #NULL is returned and the - * error is set to #DBUS_ERROR_NO_REPLY. If something else goes - * wrong, result is set to whatever is appropriate, such as - * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED. + * Blocks a certain time period while waiting for a reply. + * If no reply arrives, returns #NULL. * * @todo could use performance improvements (it keeps scanning * the whole message queue for example) and has thread issues, * see comments in source * * @param connection the connection - * @param message the message to send + * @param client_serial the reply serial to wait for * @param timeout_milliseconds timeout in milliseconds or -1 for default - * @param error return location for error message - * @returns the message that is the reply or #NULL with an error code if the - * function fails. + * @returns the message that is the reply or #NULL if no reply */ -DBusMessage * -dbus_connection_send_with_reply_and_block (DBusConnection *connection, - DBusMessage *message, - int timeout_milliseconds, - DBusError *error) +DBusMessage* +_dbus_connection_block_for_reply (DBusConnection *connection, + dbus_uint32_t client_serial, + int timeout_milliseconds) { - dbus_uint32_t client_serial; long start_tv_sec, start_tv_usec; long end_tv_sec, end_tv_usec; long tv_sec, tv_usec; DBusDispatchStatus status; _dbus_return_val_if_fail (connection != NULL, NULL); - _dbus_return_val_if_fail (message != NULL, NULL); - _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); - _dbus_return_val_if_error_is_set (error, NULL); + _dbus_return_val_if_fail (client_serial != 0, NULL); + _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); if (timeout_milliseconds == -1) timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; @@ -1792,14 +1813,6 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6) timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6; - if (!dbus_connection_send (connection, message, &client_serial)) - { - _DBUS_SET_OOM (error); - return NULL; - } - - message = NULL; - /* Flush message queue */ dbus_connection_flush (connection); @@ -1894,11 +1907,6 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, _dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %ld milliseconds and got no reply\n", (tv_sec - start_tv_sec) * 1000 + (tv_usec - start_tv_usec) / 1000); - - if (dbus_connection_get_is_connected (connection)) - dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply"); - else - dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply"); /* unlocks and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); @@ -1906,6 +1914,70 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, return NULL; } +/** + * Sends a message and blocks a certain time period while waiting for + * a reply. This function does not reenter the main loop, + * i.e. messages other than the reply are queued up but not + * processed. This function is used to do non-reentrant "method + * calls." + * + * If a normal reply is received, it is returned, and removed from the + * incoming message queue. If it is not received, #NULL is returned + * and the error is set to #DBUS_ERROR_NO_REPLY. If an error reply is + * received, it is converted to a #DBusError and returned as an error, + * then the reply message is deleted. If something else goes wrong, + * result is set to whatever is appropriate, such as + * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED. + * + * @param connection the connection + * @param message the message to send + * @param timeout_milliseconds timeout in milliseconds or -1 for default + * @param error return location for error message + * @returns the message that is the reply or #NULL with an error code if the + * function fails. + */ +DBusMessage * +dbus_connection_send_with_reply_and_block (DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds, + DBusError *error) +{ + dbus_uint32_t client_serial; + DBusMessage *reply; + + _dbus_return_val_if_fail (connection != NULL, NULL); + _dbus_return_val_if_fail (message != NULL, NULL); + _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); + _dbus_return_val_if_error_is_set (error, NULL); + + if (!dbus_connection_send (connection, message, &client_serial)) + { + _DBUS_SET_OOM (error); + return NULL; + } + + reply = _dbus_connection_block_for_reply (connection, + client_serial, + timeout_milliseconds); + + if (reply == NULL) + { + if (dbus_connection_get_is_connected (connection)) + dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply"); + else + dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply"); + + return NULL; + } + else if (dbus_set_error_from_message (error, reply)) + { + dbus_message_unref (reply); + return NULL; + } + else + return reply; +} + /** * Blocks until the outgoing message queue is empty. * @@ -2301,6 +2373,10 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) * be part of authentication or the like. * * @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY + * + * @todo right now a message filter gets run on replies to a pending + * call in here, but not in the case where we block without + * entering the main loop. * * @param connection the connection * @returns dispatch status @@ -2435,18 +2511,7 @@ dbus_connection_dispatch (DBusConnection *connection) if (pending) { - _dbus_verbose (" handing message %p to pending call\n", message); - - _dbus_assert (pending->reply == NULL); - pending->reply = message; - dbus_message_ref (pending->reply); - - dbus_pending_call_ref (pending); /* in case there's no app with a ref held */ - _dbus_connection_detach_pending_call_and_unlock (connection, pending); - - /* Must be called unlocked since it invokes app callback */ - _dbus_pending_call_notify (pending); - dbus_pending_call_unref (pending); + _dbus_pending_call_complete_and_unlock (pending, message); pending = NULL; @@ -2869,6 +2934,10 @@ dbus_connection_set_unix_user_function (DBusConnection *connection, * forgets about it. Thus the caller of this function must keep a * reference to the message handler. * + * @todo we don't run filters on messages while blocking without + * entering the main loop, since filters are run as part of + * dbus_connection_dispatch(). + * * @param connection the connection * @param handler the handler * @returns #TRUE on success, #FALSE if not enough memory. diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c index 84ca7ae0..2b6021e9 100644 --- a/dbus/dbus-pending-call.c +++ b/dbus/dbus-pending-call.c @@ -254,6 +254,31 @@ dbus_pending_call_get_reply (DBusPendingCall *pending) return pending->reply; } +/** + * Block until the pending call is completed. The blocking is as with + * dbus_connection_send_with_reply_and_block(); it does not enter the + * main loop or process other messages, it simply waits for the reply + * in question. + * + * @todo when you start blocking, the timeout is reset, but it should + * really only use time remaining since the pending call was created. + * + * @param pending the pending call + */ +void +dbus_pending_call_block (DBusPendingCall *pending) +{ + DBusMessage *message; + + message = _dbus_connection_block_for_reply (pending->connection, + pending->reply_serial, + dbus_timeout_get_interval (pending->timeout)); + + _dbus_connection_lock (pending->connection); + _dbus_pending_call_complete_and_unlock (pending, message); + dbus_message_unref (message); +} + /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h index 66f1bac5..81af872f 100644 --- a/dbus/dbus-pending-call.h +++ b/dbus/dbus-pending-call.h @@ -42,6 +42,7 @@ void dbus_pending_call_set_notify (DBusPendingCall *pen void dbus_pending_call_cancel (DBusPendingCall *pending); dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending); DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending); +void dbus_pending_call_block (DBusPendingCall *pending); DBUS_END_DECLS; -- cgit From 7c3693a53b4eba0db1aebe1edab5ded21eb7757f Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 16 Aug 2003 21:28:47 +0000 Subject: 2003-08-16 Havoc Pennington * dbus/dbus-object-registry.c (add_and_remove_objects): remove broken assertion * glib/dbus-gproxy.c: some hacking --- dbus/dbus-message.c | 4 ++++ dbus/dbus-object-registry.c | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'dbus') diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 8f25e076..5f3d01e0 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -4471,6 +4471,10 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader, * @todo we need to check that the proper named header fields exist * for each message type. * + * @todo If a message has unknown type, we should probably eat it + * right here rather than passing it out to applications. However + * it's not an error to see messages of unknown type. + * * @param loader the loader. * @returns #TRUE if we had enough memory to finish. */ diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index f1aa27de..d3d175d8 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -1274,7 +1274,6 @@ add_and_remove_objects (DBusObjectRegistry *registry) interfaces = three_interfaces; break; } - _dbus_assert (interfaces != NULL); if (!_dbus_object_registry_add_and_unlock (registry, interfaces, -- cgit 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 From 68a3c593b9e77b33614726363c7b6fd85d113021 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 18 Aug 2003 22:43:30 +0000 Subject: 2003-08-18 Havoc Pennington * dbus/dbus-hash.c (_dbus_hash_table_insert_two_strings): fix * dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix dumb bug created earlier (wrong order of args to decode_header_data()) * tools/dbus-send.c: port * tools/dbus-print-message.c (print_message): port * test/data/*messages: port all messages over * dbus/dbus-message-builder.c: support including message type * bus/driver.c: port over * bus/dispatch.c: port over to new stuff * dbus/dbus-connection.c (_dbus_connection_new_for_transport): rename disconnect signal to "Disconnected" --- dbus/dbus-connection.c | 2 +- dbus/dbus-hash.c | 29 ++++++---- dbus/dbus-message-builder.c | 42 +++++++++++++- dbus/dbus-message.c | 130 +++++++++++++++++++++++++++++++++----------- dbus/dbus-message.h | 14 +++-- dbus/dbus-protocol.h | 14 ----- dbus/dbus-string.c | 9 +++ 7 files changed, 175 insertions(+), 65 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 7be35b4c..45bbb42d 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -826,7 +826,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) goto error; disconnect_message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, - "Disconnect"); + "Disconnected"); if (disconnect_message == NULL) goto error; diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c index f4547815..044dc534 100644 --- a/dbus/dbus-hash.c +++ b/dbus/dbus-hash.c @@ -1423,17 +1423,24 @@ _dbus_hash_table_insert_two_strings (DBusHashTable *table, char *key, void *value) { - DBusPreallocatedHash *preallocated; - + DBusHashEntry *entry; + _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS); + + entry = (* table->find_function) (table, key, TRUE, NULL, NULL); - preallocated = _dbus_hash_table_preallocate_entry (table); - if (preallocated == NULL) - return FALSE; + if (entry == NULL) + return FALSE; /* no memory */ - _dbus_hash_table_insert_string_preallocated (table, preallocated, - key, value); + if (table->free_key_function && entry->key != key) + (* table->free_key_function) (entry->key); + + if (table->free_value_function && entry->value != value) + (* table->free_value_function) (entry->value); + entry->key = key; + entry->value = value; + return TRUE; } @@ -1811,8 +1818,8 @@ _dbus_hash_test (void) if (value == NULL) goto out; - if (!_dbus_hash_table_insert_string (table4, - key, value)) + if (!_dbus_hash_table_insert_two_strings (table4, + key, value)) goto out; _dbus_assert (count_entries (table1) == i + 1); @@ -1832,9 +1839,9 @@ _dbus_hash_test (void) _dbus_assert (value != NULL); _dbus_assert (strcmp (value, keys[i]) == 0); - value = _dbus_hash_table_lookup_ulong (table4, i); + value = _dbus_hash_table_lookup_two_strings (table4, keys[i]); _dbus_assert (value != NULL); - _dbus_assert (strcmp (value, keys[i]) == 0); + _dbus_assert (strcmp (value, "Value!") == 0); ++i; } diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index fc85fc32..958e57a0 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -265,6 +265,29 @@ append_saved_length (DBusString *dest, return TRUE; } +static int +message_type_from_string (const DBusString *str, + int start) +{ + const char *s; + + s = _dbus_string_get_const_data_len (str, start, + _dbus_string_get_length (str) - start); + + if (strncmp (s, "method_call", strlen ("method_call")) == 0) + return DBUS_MESSAGE_TYPE_METHOD_CALL; + else if (strncmp (s, "method_return", strlen ("method_return")) == 0) + return DBUS_MESSAGE_TYPE_METHOD_RETURN; + else if (strncmp (s, "signal", strlen ("signal")) == 0) + return DBUS_MESSAGE_TYPE_SIGNAL; + else if (strncmp (s, "error", strlen ("error")) == 0) + return DBUS_MESSAGE_TYPE_ERROR; + else if (strncmp (s, "invalid", strlen ("invalid")) == 0) + return DBUS_MESSAGE_TYPE_INVALID; + else + return -1; +} + /** * Reads the given filename, which should be in "message description * language" (look at some examples), and builds up the message data @@ -274,7 +297,7 @@ append_saved_length (DBusString *dest, * * The file format is: * @code - * VALID_HEADER normal header; byte order, padding, header len, body len, serial + * VALID_HEADER normal header; byte order, type, padding, header len, body len, serial * BIG_ENDIAN switch to big endian * LITTLE_ENDIAN switch to little endian * OPPOSITE_ENDIAN switch to opposite endian @@ -386,6 +409,13 @@ _dbus_message_data_load (DBusString *dest, { int i; DBusString name; + int message_type; + + if (_dbus_string_get_length (&line) < strlen ("VALID_HEADER ")) + { + _dbus_warn ("no args to VALID_HEADER\n"); + goto parse_failed; + } if (!_dbus_string_append_byte (dest, endian)) { @@ -393,7 +423,15 @@ _dbus_message_data_load (DBusString *dest, goto parse_failed; } - if (!_dbus_string_append_byte (dest, DBUS_MESSAGE_TYPE_METHOD_CALL)) + message_type = message_type_from_string (&line, + strlen ("VALID_HEADER ")); + if (message_type < 0) + { + _dbus_warn ("VALID_HEADER not followed by space then known message type\n"); + goto parse_failed; + } + + if (!_dbus_string_append_byte (dest, message_type)) { _dbus_warn ("could not append message type\n"); goto parse_failed; diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index e5bbcab1..c062c934 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -4049,55 +4049,115 @@ dbus_message_get_sender (DBusMessage *message) return get_string_field (message, FIELD_SENDER, NULL); } +static dbus_bool_t +_dbus_message_has_type_interface_member (DBusMessage *message, + int type, + const char *interface, + const char *method) +{ + const char *n; + + _dbus_assert (message != NULL); + _dbus_assert (interface != NULL); + _dbus_assert (method != NULL); + + if (dbus_message_get_type (message) != type) + return FALSE; + + /* Optimize by checking the short method name first + * instead of the longer interface name + */ + + n = dbus_message_get_member (message); + + if (n && strcmp (n, method) == 0) + { + n = dbus_message_get_interface (message); + + if (n && strcmp (n, interface) == 0) + return TRUE; + } + + return FALSE; +} + /** - * Checks whether the message has the given interface field. If the - * message has no interface field or has a different one, returns - * #FALSE. + * Checks whether the message is a method call with the given + * interface and member fields. If the message is not + * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or member field, + * returns #FALSE. * * @param message the message * @param interface the name to check (must not be #NULL) + * @param method the name to check (must not be #NULL) * - * @returns #TRUE if the message has the given name + * @returns #TRUE if the message is the specified method call */ dbus_bool_t -dbus_message_has_interface (DBusMessage *message, - const char *interface) +dbus_message_is_method_call (DBusMessage *message, + const char *interface, + const char *method) { - 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); + _dbus_return_val_if_fail (method != NULL, FALSE); - if (n && strcmp (n, interface) == 0) - return TRUE; - else - return FALSE; + return _dbus_message_has_type_interface_member (message, + DBUS_MESSAGE_TYPE_METHOD_CALL, + interface, method); } +/** + * Checks whether the message is a signal with the given + * interface and member fields. If the message is not + * #DBUS_MESSAGE_TYPE_SIGNAL, or has a different interface or member field, + * returns #FALSE. + * + * @param message the message + * @param interface the name to check (must not be #NULL) + * @param signal_name the name to check (must not be #NULL) + * + * @returns #TRUE if the message is the specified signal + */ +dbus_bool_t +dbus_message_is_signal (DBusMessage *message, + const char *interface, + const char *signal_name) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (interface != NULL, FALSE); + _dbus_return_val_if_fail (signal_name != NULL, FALSE); + + return _dbus_message_has_type_interface_member (message, + DBUS_MESSAGE_TYPE_SIGNAL, + interface, signal_name); +} /** - * Checks whether the message has the given member field. If the - * message has no member field or has a different one, returns #FALSE. + * Checks whether the message is an error reply with the given error + * name. If the message is not #DBUS_MESSAGE_TYPE_ERROR, or has a + * different name, returns #FALSE. * * @param message the message - * @param member the name to check (must not be #NULL) + * @param error_name the name to check (must not be #NULL) * - * @returns #TRUE if the message has the given name + * @returns #TRUE if the message is the specified error */ dbus_bool_t -dbus_message_has_member (DBusMessage *message, - const char *member) +dbus_message_is_error (DBusMessage *message, + const char *error_name) { const char *n; - - _dbus_return_val_if_fail (message != NULL, FALSE); - _dbus_return_val_if_fail (member != NULL, FALSE); + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (error_name != NULL, FALSE); + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) + return FALSE; + n = dbus_message_get_member (message); - if (n && strcmp (n, member) == 0) + if (n && strcmp (n, error_name) == 0) return TRUE; else return FALSE; @@ -4507,7 +4567,10 @@ decode_header_data (const DBusString *data, int type; if (header_len < 16) - return FALSE; + { + _dbus_verbose ("Header length %d is too short\n", header_len); + return FALSE; + } i = 0; while (i < FIELD_LAST) @@ -4532,7 +4595,10 @@ decode_header_data (const DBusString *data, pos = _DBUS_ALIGN_VALUE (pos, 4); if ((pos + 4) > header_len) - return FALSE; + { + _dbus_verbose ("not enough space remains in header for header field value\n"); + return FALSE; + } field =_dbus_string_get_const_data_len (data, pos, 4); pos += 4; @@ -4809,8 +4875,9 @@ _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, message_type, + if (!decode_header_data (&loader->data, header_len, byte_order, + message_type, fields, &header_padding)) { _dbus_verbose ("Header was invalid\n"); @@ -5919,10 +5986,11 @@ process_test_subdir (const DBusString *test_base_dir, printf (" %s\n", _dbus_string_get_const_data (&filename)); - _dbus_verbose (" expecting %s\n", + _dbus_verbose (" expecting %s for %s\n", validity == _DBUS_MESSAGE_VALID ? "valid" : (validity == _DBUS_MESSAGE_INVALID ? "invalid" : - (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown"))); + (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")), + _dbus_string_get_const_data (&filename)); if (! (*function) (&full_path, is_raw, validity, user_data)) { @@ -6245,8 +6313,8 @@ _dbus_message_test (const char *test_data_dir) "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_assert (dbus_message_is_method_call (message, "Foo.TestInterface", + "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")); diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index dc204585..526cf971 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -91,12 +91,14 @@ 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_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_is_method_call (DBusMessage *message, + const char *interface, + const char *method); +dbus_bool_t dbus_message_is_signal (DBusMessage *message, + const char *interface, + const char *signal_name); +dbus_bool_t dbus_message_is_error (DBusMessage *message, + const char *error_name); dbus_bool_t dbus_message_has_destination (DBusMessage *message, const char *service); dbus_bool_t dbus_message_has_sender (DBusMessage *message, diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index a1f4a722..21c06a76 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -106,20 +106,6 @@ extern "C" { * 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 848135fc..98b4c60e 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -2853,6 +2853,9 @@ _dbus_string_validate_nul (const DBusString *str, * * @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 + * interface name * * @param str the string * @param start first byte index to check @@ -2911,6 +2914,9 @@ _dbus_string_validate_interface (const DBusString *str, * @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 + * member name + * * @param str the string * @param start first byte index to check * @param len number of bytes to check @@ -2991,6 +2997,9 @@ _dbus_string_validate_error_name (const DBusString *str, * * @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 + * service name * * @param str the string * @param start first byte index to check -- cgit From d0c588575e3e2911eacb098fac26f02d1010cbfd Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 20 Aug 2003 14:48:04 +0000 Subject: 2003-08-19 Havoc Pennington * dbus/dbus-message.c (decode_string_field): support FIELD_SENDER (dbus_message_is_error): fix this function * bus/dbus-daemon-1.1: clarify logic on when / rules match * bus/policy.c (bus_client_policy_check_can_receive): fix code to reflect clarified man page (bus_client_policy_check_can_send): ditto * bus/session.conf.in: fixup * bus/system.conf.in: fixup --- dbus/dbus-message.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index c062c934..9b87c3d9 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -4155,7 +4155,7 @@ dbus_message_is_error (DBusMessage *message, if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) return FALSE; - n = dbus_message_get_member (message); + n = dbus_message_get_error_name (message); if (n && strcmp (n, error_name) == 0) return TRUE; @@ -4529,7 +4529,8 @@ decode_string_field (const DBusString *data, return FALSE; } } - else if (field == FIELD_SERVICE) + else if (field == FIELD_SERVICE || + field == FIELD_SENDER) { if (!_dbus_string_validate_service (&tmp, 0, _dbus_string_get_length (&tmp))) { @@ -4537,7 +4538,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"); -- cgit From 24f411a6a10e4838f57595720642ce83ceae814c Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 25 Aug 2003 14:56:53 +0000 Subject: 2003-08-25 Havoc Pennington Just noticed that dbus_message_test is hosed, I wonder when I broke that. I thought make check was passing earlier... * dbus/dbus-object-tree.c: add new "object tree" to match DCOP container tree, will replace most of dbus-object-registry * dbus/dbus-string.c (_dbus_string_append_printf_valist): fix C99 screwup --- dbus/Makefile.am | 2 + dbus/dbus-connection.h | 48 ++++ dbus/dbus-message-builder.c | 2 +- dbus/dbus-object-tree.c | 609 ++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-object-tree.h | 48 ++++ dbus/dbus-string.c | 2 +- dbus/dbus-test.c | 6 + dbus/dbus-test.h | 1 + 8 files changed, 716 insertions(+), 2 deletions(-) create mode 100644 dbus/dbus-object-tree.c create mode 100644 dbus/dbus-object-tree.h (limited to 'dbus') diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 3537b935..e59877e6 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -49,6 +49,8 @@ DBUS_LIB_SOURCES= \ dbus-objectid.c \ dbus-object-registry.c \ dbus-object-registry.h \ + dbus-object-tree.c \ + dbus-object-tree.h \ dbus-pending-call.c \ dbus-resources.c \ dbus-resources.h \ diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index ef106524..7204c8ed 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -198,6 +198,54 @@ void dbus_connection_send_preallocated (DBusConnection dbus_uint32_t *client_serial); +/* Object tree functionality */ + +typedef struct DBusObjectTreeVTable DBusObjectTreeVTable; + +typedef void (* DBusObjectTreeUnregisterFunction) (DBusConnection *connection, + const char **path, + void *user_data); +typedef DBusHandlerResult (* DBusObjectTreeMessageFunction) (DBusConnection *connection, + DBusMessage *message, + void *user_data); +typedef dbus_bool_t (* DBusObjectTreeSubdirsFunction) (DBusConnection *connection, + const char **path, + char ***subdirs, + int *n_subdirs, + void *user_data); +typedef dbus_bool_t (* DBusObjectTreeObjectsFunction) (DBusConnection *connection, + const char **path, + DBusObjectID **object_ids, + int *n_object_ids, + void *user_data); +typedef dbus_bool_t (* DBusObjectTreeMethodsFunction) (DBusConnection *connection, + const char **path, + DBusObjectID **object_ids, + int *n_object_ids, + void *user_data); + +struct DBusObjectTreeVTable +{ + DBusObjectTreeUnregisterFunction unregister_function; + DBusObjectTreeMessageFunction message_function; + DBusObjectTreeSubdirsFunction subdirs_function; + DBusObjectTreeObjectsFunction objects_function; + DBusObjectTreeMethodsFunction methods_function; + + void (* dbus_internal_pad1) (void *); + void (* dbus_internal_pad2) (void *); + void (* dbus_internal_pad3) (void *); + void (* dbus_internal_pad4) (void *); +}; + +dbus_bool_t dbus_connection_register_object_tree (DBusConnection *connection, + const char **path, + const DBusObjectTreeVTable *vtable, + void *user_data); +void dbus_connection_unregister_object_tree (DBusConnection *connection, + const char **path); + + DBUS_END_DECLS; #endif /* DBUS_CONNECTION_H */ diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 958e57a0..f779c8c1 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -411,7 +411,7 @@ _dbus_message_data_load (DBusString *dest, DBusString name; int message_type; - if (_dbus_string_get_length (&line) < strlen ("VALID_HEADER ")) + if (_dbus_string_get_length (&line) < (int) strlen ("VALID_HEADER ")) { _dbus_warn ("no args to VALID_HEADER\n"); goto parse_failed; diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c new file mode 100644 index 00000000..7f7e6011 --- /dev/null +++ b/dbus/dbus-object-tree.c @@ -0,0 +1,609 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "dbus-object-tree.h" +#include "dbus-connection-internal.h" +#include "dbus-internals.h" +#include "dbus-hash.h" +#include "dbus-protocol.h" +#include +#include + +/** + * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship + * @ingroup DBusInternals + * @brief DBusObjectTree is used by DBusConnection to track the object tree + * + * Types and functions related to DBusObjectTree. These + * are all internal. + * + * @{ + */ + +typedef struct DBusObjectSubtree DBusObjectSubtree; + +DBusObjectSubtree* _dbus_object_subtree_new (const char **path, + const DBusObjectTreeVTable *vtable, + void *user_data); +void _dbus_object_subtree_ref (DBusObjectSubtree *subtree); +void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); + +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; +}; + +struct DBusObjectSubtree +{ + int refcount; + char **path; + int n_path_elements; + DBusObjectTreeVTable vtable; + void *user_data; +}; + +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; + + return tree; + + oom: + if (tree) + { + dbus_free (tree); + } + + return NULL; +} + +void +_dbus_object_tree_ref (DBusObjectTree *tree) +{ + _dbus_assert (tree->refcount > 0); + + tree->refcount += 1; +} + +void +_dbus_object_tree_unref (DBusObjectTree *tree) +{ + _dbus_assert (tree->refcount > 0); + + tree->refcount -= 1; + + if (tree->refcount == 0) + { + if (tree->subtrees) + { + int i; + i = 0; + while (i < tree->n_subtrees) + { + _dbus_object_subtree_unref (tree->subtrees[i]); + ++i; + } + } + + dbus_free (tree); + } +} + +static int +path_cmp (const char **path_a, + const char **path_b) +{ + /* The comparison is as if the path were flattened + * into a single string. strcmp() considers + * a shorter string less than a longer string + * if the shorter string is the initial part + * of the longer + */ + 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); +} + +static int +subtree_qsort_cmp (const void *a, + const void *b) +{ + DBusObjectSubtree **subtree_a_p = (void*) a; + DBusObjectSubtree **subtree_b_p = (void*) b; + + return subtree_cmp (*subtree_a_p, *subtree_b_p); +} + +/* Returns TRUE if a is a subdir of b or vice + * versa. This is the case if one is a subpath + * of the other. + */ +static dbus_bool_t +path_overlaps (const char **path_a, + const char **path_b) +{ + int i; + + i = 0; + while (path_a[i] != NULL) + { + int v; + + if (path_b[i] == NULL) + return TRUE; /* b is subpath of a */ + + _dbus_assert (path_a[i] != NULL); + _dbus_assert (path_b[i] != NULL); + + v = strcmp (path_a[i], path_b[i]); + + if (v != 0) + return FALSE; /* they overlap until here and then are different, + * not overlapping + */ + + ++i; + } + + /* b is either the same as or a superset of a */ + _dbus_assert (path_a[i] == NULL); + return TRUE; +} + +static dbus_bool_t +find_subtree (DBusObjectTree *tree, + const char **path, + int *idx_p) +{ + int i; + + if (tree->subtrees == NULL) + return FALSE; + + if (!tree->subtrees_sorted) + { + qsort (tree->subtrees, + tree->n_subtrees, + sizeof (DBusObjectSubtree*), + subtree_qsort_cmp); + tree->subtrees_sorted = TRUE; + } + + /* FIXME this should be a binary search, + * as that's the whole point of the sorting + */ + i = 0; + while (i < tree->n_subtrees) + { + int v; + + v = path_cmp (path, + (const char**) tree->subtrees[i]->path); + if (v == 0) + { + if (idx_p) + *idx_p = i; + return TRUE; + } + else if (v > 0) + return FALSE; + + ++i; + } + + return FALSE; +} + +#ifndef DBUS_DISABLE_CHECKS +static void +check_overlap (DBusObjectTree *tree, + const char **path) +{ + int i; + + i = 0; + while (i < tree->n_subtrees) + { + if (path_overlaps (path, (const char**) tree->subtrees[i]->path)) + { + _dbus_warn ("New path (path[0] = %s) overlaps old path (path[0] = %s)\n", + path[0], tree->subtrees[i]->path[0]); + } + ++i; + } +} +#endif + +/** + * Registers a new subtree in the global object tree. + * + * @param tree the global object tree + * @param path NULL-terminated array of path elements giving path to subtree + * @param vtable the vtable used to traverse this subtree + * @param user_data user data to pass to methods in the vtable + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_object_tree_register (DBusObjectTree *tree, + const char **path, + const DBusObjectTreeVTable *vtable, + void *user_data) +{ + DBusObjectSubtree *subtree; + DBusObjectSubtree **new_subtrees; + int new_n_subtrees; + + _dbus_assert (path != NULL); +#ifndef DBUS_DISABLE_CHECKS + check_overlap (tree, path); +#endif + _dbus_assert (path[0] != NULL); + + subtree = _dbus_object_subtree_new (path, vtable, user_data); + 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); + if (new_subtrees == NULL) + { + _DBUS_ZERO (subtree->vtable); /* to avoid assertion in unref() */ + _dbus_object_subtree_unref (subtree); + return FALSE; + } + + tree->subtrees[tree->n_subtrees] = subtree; + tree->subtrees_sorted = FALSE; + tree->n_subtrees = new_n_subtrees; + tree->subtrees = new_subtrees; + + return TRUE; +} + +/** + * Unregisters an object subtree that was registered with the + * same path. + * + * @param tree the global object tree + * @param path path to the subtree (same as the one passed to _dbus_object_tree_register()) + */ +void +_dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, + const char **path) +{ + int i; + DBusObjectSubtree *subtree; + + _dbus_assert (path != NULL); + _dbus_assert (path[0] != NULL); + + if (!find_subtree (tree, path, &i)) + { + _dbus_warn ("Attempted to unregister subtree (path[0] = %s) which isn't registered\n", + path[0]); + return; + } + + 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_object_subtree_ref (subtree); + + /* Unlock and call application code */ + _dbus_connection_unlock (tree->connection); + + if (subtree->vtable.unregister_function) + { + (* subtree->vtable.unregister_function) (tree->connection, + (const char**) subtree->path, + subtree->user_data); + _DBUS_ZERO (subtree->vtable); + } +} + +/** + * Tries to dispatch a message by directing it to the object tree + * node listed in the message header, if any. + * + * @param tree the global object tree + * @param message the message to dispatch + * @returns whether message was handled successfully + */ +DBusHandlerResult +_dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, + DBusMessage *message) +{ + + +} + +DBusObjectSubtree* +_dbus_object_subtree_new (const char **path, + const DBusObjectTreeVTable *vtable, + void *user_data) +{ + DBusObjectSubtree *subtree; + + subtree = dbus_new0 (DBusObjectSubtree, 1); + if (subtree == NULL) + goto oom; + + _dbus_assert (path != NULL); + _dbus_assert (path[0] != NULL); + + subtree->path = _dbus_dup_string_array (path); + if (subtree->path == NULL) + goto oom; + + subtree->vtable = *vtable; + subtree->user_data = user_data; + + subtree->refcount = 1; + + /* count path elements */ + while (subtree->path[subtree->n_path_elements]) + subtree->n_path_elements += 1; + + return subtree; + + oom: + if (subtree) + { + dbus_free_string_array (subtree->path); + dbus_free (subtree); + } + + return NULL; +} + +void +_dbus_object_subtree_ref (DBusObjectSubtree *subtree) +{ + _dbus_assert (subtree->refcount > 0); + + subtree->refcount += 1; +} + +void +_dbus_object_subtree_unref (DBusObjectSubtree *subtree) +{ + _dbus_assert (subtree->refcount > 0); + + subtree->refcount -= 1; + + if (subtree->refcount == 0) + { + _dbus_assert (subtree->vtable.unregister_function == NULL); + + dbus_free_string_array (subtree->path); + + dbus_free (subtree); + } +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +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; + DBusObjectTreeVTable 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; + + _dbus_assert (subtree_cmp (subtree1, subtree2) == expected); + + retval = TRUE; + + out: + + if (subtree1) + _dbus_object_subtree_unref (subtree1); + + if (subtree2) + _dbus_object_subtree_unref (subtree2); + + 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); + } + + return retval; +} + +static void +test_path_overlap (const char **path1, + const char **path2, + dbus_bool_t expected) +{ + _dbus_assert (path_overlaps (path1, path2) == expected); + _dbus_assert (path_overlaps (path2, path1) == expected); +} + +static dbus_bool_t +object_tree_test_iteration (void *data) +{ + const char *path1[] = { "foo", NULL }; + const char *path2[] = { "foo", "bar", NULL }; + const char *path3[] = { "foo", "bar", "baz", NULL }; + const char *path4[] = { "foo", "bar", "boo", NULL }; + const char *path5[] = { "blah", NULL }; + DBusObjectSubtree *subtree1; + DBusObjectSubtree *subtree2; + DBusObjectTree *tree; + + tree = NULL; + subtree1 = NULL; + subtree2 = NULL; + + test_path_overlap (path1, path1, TRUE); + test_path_overlap (path1, path2, TRUE); + test_path_overlap (path1, path3, TRUE); + test_path_overlap (path1, path4, TRUE); + test_path_overlap (path1, path5, FALSE); + + test_path_overlap (path2, path2, TRUE); + test_path_overlap (path2, path3, TRUE); + test_path_overlap (path2, path4, TRUE); + test_path_overlap (path2, path5, FALSE); + + test_path_overlap (path3, path3, TRUE); + test_path_overlap (path3, path4, FALSE); + test_path_overlap (path3, path5, FALSE); + + test_path_overlap (path4, path4, TRUE); + test_path_overlap (path4, path5, FALSE); + + test_path_overlap (path5, path5, 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; + + out: + if (subtree1) + _dbus_object_subtree_unref (subtree1); + if (subtree2) + _dbus_object_subtree_unref (subtree2); + if (tree) + _dbus_object_tree_unref (tree); + + return TRUE; +} + +/** + * @ingroup DBusObjectTree + * Unit test for DBusObjectTree + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_object_tree_test (void) +{ + _dbus_test_oom_handling ("object tree", + object_tree_test_iteration, + NULL); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h new file mode 100644 index 00000000..06033333 --- /dev/null +++ b/dbus/dbus-object-tree.h @@ -0,0 +1,48 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object-tree.h DBusObjectTree (internals of DBusConnection) + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_OBJECT_TREE_H +#define DBUS_OBJECT_TREE_H + +#include + +DBUS_BEGIN_DECLS; + +typedef struct DBusObjectTree DBusObjectTree; + +DBusObjectTree* _dbus_object_tree_new (DBusConnection *connection); +void _dbus_object_tree_ref (DBusObjectTree *tree); +void _dbus_object_tree_unref (DBusObjectTree *tree); + +dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, + const char **path, + const DBusObjectTreeVTable *vtable, + void *user_data); +void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, + const char **path); +DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, + DBusMessage *message); + + +DBUS_END_DECLS; + +#endif /* DBUS_OBJECT_TREE_H */ diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 98b4c60e..75b38b9d 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -1002,9 +1002,9 @@ _dbus_string_append_printf_valist (DBusString *str, const char *format, va_list args) { - DBUS_STRING_PREAMBLE (str); int len; char c; + DBUS_STRING_PREAMBLE (str); /* Measure the message length without terminating nul */ len = vsnprintf (&c, 1, format, args); diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 8a99d179..2ab7fc27 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -112,6 +112,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) check_memleaks (); + printf ("%s: running object tree tests\n", "dbus-test"); + if (!_dbus_object_tree_test ()) + die ("object tree"); + + check_memleaks (); + printf ("%s: running object tests\n", "dbus-test"); if (!_dbus_object_test ()) die ("object"); diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index 276e8f9e..b6c02669 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -56,6 +56,7 @@ dbus_bool_t _dbus_memory_test (void); dbus_bool_t _dbus_object_test (void); dbus_bool_t _dbus_object_id_test (void); dbus_bool_t _dbus_object_registry_test (void); +dbus_bool_t _dbus_object_tree_test (void); dbus_bool_t _dbus_pending_call_test (const char *test_data_dir); void dbus_internal_do_not_use_run_tests (const char *test_data_dir); -- cgit From 8d38a2e2c5dc95de992c4d856ec1b0c0948bca3e Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 29 Aug 2003 01:05:00 +0000 Subject: 2003-08-28 Havoc Pennington purge DBusObjectID * dbus/dbus-connection.c: port to no ObjectID, create a DBusObjectTree, rename ObjectTree to ObjectPath in public API * dbus/dbus-connection.h (struct DBusObjectTreeVTable): delete everything except UnregisterFunction and MessageFunction * dbus/dbus-marshal.c: port away from DBusObjectID, add DBUS_TYPE_OBJECT_PATH * dbus/dbus-object-registry.[hc], dbus/dbus-object.[hc], dbus/dbus-objectid.[hc]: remove these, we are moving to path-based object IDs --- dbus/Makefile.am | 6 - dbus/dbus-bus.c | 1 + dbus/dbus-connection-internal.h | 3 +- dbus/dbus-connection.c | 112 ++-- dbus/dbus-connection.h | 59 +- dbus/dbus-internals.h | 1 - dbus/dbus-marshal.c | 105 ++- dbus/dbus-marshal.h | 30 +- dbus/dbus-object-registry.c | 1399 --------------------------------------- dbus/dbus-object-registry.h | 57 -- dbus/dbus-object-tree.c | 27 +- dbus/dbus-object-tree.h | 3 +- dbus/dbus-object.c | 349 ---------- dbus/dbus-object.h | 90 --- dbus/dbus-objectid.c | 470 ------------- dbus/dbus-objectid.h | 75 --- dbus/dbus-protocol.h | 4 +- dbus/dbus-test.c | 18 - dbus/dbus-test.h | 3 - dbus/dbus-threads.c | 1 - dbus/dbus.h | 4 +- 21 files changed, 150 insertions(+), 2667 deletions(-) delete mode 100644 dbus/dbus-object-registry.c delete mode 100644 dbus/dbus-object-registry.h delete mode 100644 dbus/dbus-object.c delete mode 100644 dbus/dbus-object.h delete mode 100644 dbus/dbus-objectid.c delete mode 100644 dbus/dbus-objectid.h (limited to 'dbus') diff --git a/dbus/Makefile.am b/dbus/Makefile.am index e59877e6..f8509cce 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -17,8 +17,6 @@ dbusinclude_HEADERS= \ dbus-memory.h \ dbus-message.h \ dbus-message-handler.h \ - dbus-object.h \ - dbus-objectid.h \ dbus-pending-call.h \ dbus-protocol.h \ dbus-server.h \ @@ -45,10 +43,6 @@ DBUS_LIB_SOURCES= \ dbus-message.c \ dbus-message-handler.c \ dbus-message-internal.h \ - dbus-object.c \ - dbus-objectid.c \ - dbus-object-registry.c \ - dbus-object-registry.h \ dbus-object-tree.c \ dbus-object-tree.h \ dbus-pending-call.c \ diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 445606e2..89a2d12b 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -25,6 +25,7 @@ #include "dbus-bus.h" #include "dbus-protocol.h" #include "dbus-internals.h" +#include "dbus-message.h" #include /** diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index f26c92e6..93b1b4a3 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -86,8 +86,7 @@ void _dbus_message_handler_remove_connection (DBusMessageHandl DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandler *handler, DBusConnection *connection, DBusMessage *message); -void _dbus_connection_init_id (DBusConnection *connection, - DBusObjectID *id); + DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, int timeout_milliseconds, DBusTimeoutHandler timeout_handler); diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 45bbb42d..0c384594 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -35,9 +35,9 @@ #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-dataslot.h" -#include "dbus-object-registry.h" #include "dbus-string.h" #include "dbus-pending-call.h" +#include "dbus-object-tree.h" #if 0 #define CONNECTION_LOCK(connection) do { \ @@ -179,7 +179,7 @@ struct DBusConnection DBusList *link_cache; /**< A cache of linked list links to prevent contention * for the global linked list mempool lock */ - DBusObjectRegistry *objects; /**< Objects registered with this connection */ + DBusObjectTree *objects; /**< Object path handlers registered with this connection */ }; static void _dbus_connection_remove_timeout_locked (DBusConnection *connection, @@ -775,7 +775,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) DBusList *disconnect_link; DBusMessage *disconnect_message; DBusCounter *outgoing_counter; - DBusObjectRegistry *objects; + DBusObjectTree *objects; watch_list = NULL; connection = NULL; @@ -839,7 +839,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (outgoing_counter == NULL) goto error; - objects = _dbus_object_registry_new (connection); + objects = _dbus_object_tree_new (connection); if (objects == NULL) goto error; @@ -908,7 +908,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) _dbus_counter_unref (outgoing_counter); if (objects) - _dbus_object_registry_unref (objects); + _dbus_object_tree_unref (objects); return NULL; } @@ -1048,25 +1048,6 @@ _dbus_connection_handle_watch (DBusWatch *watch, return retval; } -/** - * Get the server ID to be used in the object ID for an object - * registered with this connection. - * - * @todo implement this function - * - * @param connection the connection. - * @returns the portion of the object ID - */ -void -_dbus_connection_init_id (DBusConnection *connection, - DBusObjectID *object_id) -{ - /* FIXME */ - dbus_object_id_set_server_bits (object_id, 15); - dbus_object_id_set_client_bits (object_id, 31); - dbus_object_id_set_is_server_bit (object_id, FALSE); -} - /** @} */ /** @@ -1178,7 +1159,7 @@ _dbus_connection_last_unref (DBusConnection *connection) _dbus_assert (!_dbus_transport_get_is_connected (connection->transport)); /* ---- We're going to call various application callbacks here, hope it doesn't break anything... */ - _dbus_object_registry_free_all_unlocked (connection->objects); + _dbus_object_tree_free_all_unlocked (connection->objects); dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); dbus_connection_set_wakeup_main_function (connection, NULL, NULL, NULL); @@ -1204,7 +1185,7 @@ _dbus_connection_last_unref (DBusConnection *connection) link = next; } - _dbus_object_registry_unref (connection->objects); + _dbus_object_tree_unref (connection->objects); _dbus_hash_table_unref (connection->pending_replies); connection->pending_replies = NULL; @@ -2547,8 +2528,8 @@ dbus_connection_dispatch (DBusConnection *connection) dbus_message_get_interface (message) : "no interface"); - result = _dbus_object_registry_handle_and_unlock (connection->objects, - message); + result = _dbus_object_tree_dispatch_and_unlock (connection->objects, + message); CONNECTION_LOCK (connection); @@ -3026,67 +3007,58 @@ dbus_connection_remove_filter (DBusConnection *connection, } /** - * Registers an object with the connection. This object is assigned an - * object ID, and will be visible under this ID and with the provided - * interfaces to the peer application on the other end of the - * connection. The object instance should be passed in as object_impl; - * the instance can be any datatype, as long as it fits in a void*. + * Registers a handler for a given subsection of the object hierarchy. + * The given vtable handles messages at or below the given path. * - * As a side effect of calling this function, the "registered" - * callback in the #DBusObjectVTable will be invoked. - * - * If the object is deleted, be sure to unregister it with - * dbus_connection_unregister_object() or it will continue to get - * messages. * - * @param connection the connection to register the instance with - * @param interfaces #NULL-terminated array of interface names the instance supports - * @param vtable virtual table of functions for manipulating the instance - * @param object_impl object instance - * @param object_id if non-#NULL, object ID to initialize with the new object's ID - * @returns #FALSE if not enough memory to register the object instance + * @param connection the connection + * @param path #NULL-terminated array of path elements + * @param vtable the virtual table + * @param user_data data to pass to functions in the vtable + * @returns #FALSE if not enough memory */ dbus_bool_t -dbus_connection_register_object (DBusConnection *connection, - const char **interfaces, - const DBusObjectVTable *vtable, - void *object_impl, - DBusObjectID *object_id) +dbus_connection_register_object_path (DBusConnection *connection, + const char **path, + const DBusObjectPathVTable *vtable, + void *user_data) { + dbus_bool_t retval; + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] != NULL, FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); - _dbus_return_val_if_fail (vtable->dbus_internal_pad1 == NULL, FALSE); - _dbus_return_val_if_fail (vtable->dbus_internal_pad2 == NULL, FALSE); - _dbus_return_val_if_fail (vtable->dbus_internal_pad3 == NULL, FALSE); - + CONNECTION_LOCK (connection); - return _dbus_object_registry_add_and_unlock (connection->objects, - interfaces, - vtable, - object_impl, - object_id); + retval = _dbus_object_tree_register (connection->objects, path, vtable, + user_data); + + CONNECTION_UNLOCK (connection); + + return retval; } /** - * Reverses the effects of dbus_connection_register_object(), - * and invokes the "unregistered" callback in the #DBusObjectVTable - * for the given object. The passed-in object ID must be a valid, - * registered object ID or the results are undefined. + * Unregisters the handler registered with exactly the given path. + * It's a bug to call this function for a path that isn't registered. * - * @param connection the connection to unregister the object ID from - * @param object_id the object ID to unregister + * @param connection the connection + * @param path the #NULL-terminated array of path elements */ void -dbus_connection_unregister_object (DBusConnection *connection, - const DBusObjectID *object_id) +dbus_connection_unregister_object_path (DBusConnection *connection, + const char **path) { - _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (path != NULL); + _dbus_return_if_fail (path[0] != NULL); CONNECTION_LOCK (connection); - return _dbus_object_registry_remove_and_unlock (connection->objects, - object_id); + return _dbus_object_tree_unregister_and_unlock (connection->objects, + path); } static DBusDataSlotAllocator slot_allocator; diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 7204c8ed..12ad0682 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-connection.h DBusConnection object * - * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 * @@ -29,7 +29,7 @@ #include #include -#include +#include DBUS_BEGIN_DECLS; @@ -38,6 +38,8 @@ typedef struct DBusTimeout DBusTimeout; typedef struct DBusMessageHandler DBusMessageHandler; typedef struct DBusPreallocatedSend DBusPreallocatedSend; typedef struct DBusPendingCall DBusPendingCall; +typedef struct DBusConnection DBusConnection; +typedef struct DBusObjectPathVTable DBusObjectPathVTable; typedef enum { @@ -57,6 +59,13 @@ typedef enum DBUS_DISPATCH_NEED_MEMORY /**< More memory is needed to continue. */ } DBusDispatchStatus; +typedef enum +{ + DBUS_HANDLER_RESULT_HANDLED, /**< Message has had its effect */ + DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect */ + DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory to return another result */ +} DBusHandlerResult; + typedef dbus_bool_t (* DBusAddWatchFunction) (DBusWatch *watch, void *data); typedef void (* DBusWatchToggledFunction) (DBusWatch *watch, @@ -159,16 +168,6 @@ dbus_bool_t dbus_connection_add_filter (DBusConnection *connection, void dbus_connection_remove_filter (DBusConnection *connection, DBusMessageHandler *handler); -/* Objects */ -dbus_bool_t dbus_connection_register_object (DBusConnection *connection, - const char **interfaces, - const DBusObjectVTable *vtable, - void *object_impl, - DBusObjectID *object_id); -void dbus_connection_unregister_object (DBusConnection *connection, - const DBusObjectID *object_id); - - /* Other */ dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p); void dbus_connection_free_data_slot (dbus_int32_t *slot_p); @@ -200,37 +199,17 @@ void dbus_connection_send_preallocated (DBusConnection /* Object tree functionality */ -typedef struct DBusObjectTreeVTable DBusObjectTreeVTable; - -typedef void (* DBusObjectTreeUnregisterFunction) (DBusConnection *connection, +typedef void (* DBusObjectPathUnregisterFunction) (DBusConnection *connection, const char **path, void *user_data); -typedef DBusHandlerResult (* DBusObjectTreeMessageFunction) (DBusConnection *connection, +typedef DBusHandlerResult (* DBusObjectPathMessageFunction) (DBusConnection *connection, DBusMessage *message, void *user_data); -typedef dbus_bool_t (* DBusObjectTreeSubdirsFunction) (DBusConnection *connection, - const char **path, - char ***subdirs, - int *n_subdirs, - void *user_data); -typedef dbus_bool_t (* DBusObjectTreeObjectsFunction) (DBusConnection *connection, - const char **path, - DBusObjectID **object_ids, - int *n_object_ids, - void *user_data); -typedef dbus_bool_t (* DBusObjectTreeMethodsFunction) (DBusConnection *connection, - const char **path, - DBusObjectID **object_ids, - int *n_object_ids, - void *user_data); -struct DBusObjectTreeVTable +struct DBusObjectPathVTable { - DBusObjectTreeUnregisterFunction unregister_function; - DBusObjectTreeMessageFunction message_function; - DBusObjectTreeSubdirsFunction subdirs_function; - DBusObjectTreeObjectsFunction objects_function; - DBusObjectTreeMethodsFunction methods_function; + DBusObjectPathUnregisterFunction unregister_function; + DBusObjectPathMessageFunction message_function; void (* dbus_internal_pad1) (void *); void (* dbus_internal_pad2) (void *); @@ -238,11 +217,11 @@ struct DBusObjectTreeVTable void (* dbus_internal_pad4) (void *); }; -dbus_bool_t dbus_connection_register_object_tree (DBusConnection *connection, +dbus_bool_t dbus_connection_register_object_path (DBusConnection *connection, const char **path, - const DBusObjectTreeVTable *vtable, + const DBusObjectPathVTable *vtable, void *user_data); -void dbus_connection_unregister_object_tree (DBusConnection *connection, +void dbus_connection_unregister_object_path (DBusConnection *connection, const char **path); diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 6d120f1b..1c0f7314 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -234,7 +234,6 @@ _DBUS_DECLARE_GLOBAL_LOCK (server_slots); _DBUS_DECLARE_GLOBAL_LOCK (message_slots); _DBUS_DECLARE_GLOBAL_LOCK (atomic); _DBUS_DECLARE_GLOBAL_LOCK (message_handler); -_DBUS_DECLARE_GLOBAL_LOCK (callback_object); _DBUS_DECLARE_GLOBAL_LOCK (bus); _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); _DBUS_DECLARE_GLOBAL_LOCK (system_users); diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index aaf97c7c..449dd33a 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -80,7 +80,6 @@ typedef union dbus_uint64_t u; #endif double d; - DBusObjectID object_id; } DBusOctets8; static DBusOctets8 @@ -426,26 +425,27 @@ _dbus_marshal_set_string (DBusString *str, } /** - * Sets the existing marshaled object ID at the given offset to a new - * value. The given offset must point to an existing object ID or this + * Sets the existing marshaled object path at the given offset to a new + * value. The given offset must point to an existing object path or this * function doesn't make sense. * - * @param str the string to write the marshalled string to - * @param offset the byte offset where string should be written + * @todo implement this function + * + * @param str the string to write the marshalled path to + * @param offset the byte offset where path should be written * @param byte_order the byte order to use - * @param value the new value + * @param path the new path + * @param path_len number of elements in the path */ void -_dbus_marshal_set_object_id (DBusString *str, - int byte_order, - int offset, - const DBusObjectID *value) +_dbus_marshal_set_object_path (DBusString *str, + int byte_order, + int offset, + const char **path, + int path_len) { - DBusOctets8 r; - - r.object_id = *value; - - set_8_octets (str, byte_order, offset, r); + + /* FIXME */ } static dbus_bool_t @@ -870,23 +870,23 @@ _dbus_marshal_string_array (DBusString *str, } /** - * Marshals an object ID value. + * 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 - * @param value the value + * @param path the path + * @param path_len length of the path * @returns #TRUE on success */ dbus_bool_t -_dbus_marshal_object_id (DBusString *str, - int byte_order, - const DBusObjectID *value) +_dbus_marshal_object_path (DBusString *str, + int byte_order, + const char **path, + int path_len) { - DBusOctets8 r; - - r.object_id = *value; - - return marshal_8_octets (str, byte_order, r); + return TRUE; } static dbus_uint32_t @@ -1439,26 +1439,26 @@ _dbus_demarshal_string_array (const DBusString *str, } /** - * Demarshals an object ID. + * Demarshals an object path. * + * @todo implement this function + * * @param str the string containing the data * @param byte_order the byte order * @param pos the position in the string * @param new_pos the new position of the string - * @param value address to store new object ID + * @param path address to store new object path + * @param path_len length of stored path */ -void -_dbus_demarshal_object_id (const DBusString *str, - int byte_order, - int pos, - int *new_pos, - DBusObjectID *value) +dbus_bool_t +_dbus_demarshal_object_path (const DBusString *str, + int byte_order, + int pos, + int *new_pos, + char ***path, + int *path_len) { - DBusOctets8 r; - - r = demarshal_8_octets (str, byte_order, pos, new_pos); - - *value = r.object_id; + } /** @@ -1509,7 +1509,6 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str, case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: - case DBUS_TYPE_OBJECT_ID: case DBUS_TYPE_DOUBLE: *end_pos = _DBUS_ALIGN_VALUE (pos, 8) + 8; @@ -1541,7 +1540,8 @@ _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; @@ -1718,6 +1718,7 @@ validate_array_data (const DBusString *str, case DBUS_TYPE_NIL: break; + case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_STRING: case DBUS_TYPE_NAMED: case DBUS_TYPE_ARRAY: @@ -1771,7 +1772,6 @@ validate_array_data (const DBusString *str, case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: - case DBUS_TYPE_OBJECT_ID: /* Call validate arg one time to check alignment padding * at start of array */ @@ -1802,7 +1802,9 @@ validate_array_data (const DBusString *str, * * @todo For array types that can't be invalid, we should not * walk the whole array validating it. e.g. just skip all the - * int values in an int array. + * int values in an int array. (maybe this is already done now -hp) + * + * @todo support DBUS_TYPE_OBJECT_PATH * * @param str a string * @param byte_order the byte order to use @@ -1899,7 +1901,6 @@ _dbus_marshal_validate_arg (const DBusString *str, case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: - case DBUS_TYPE_OBJECT_ID: { int align_8 = _DBUS_ALIGN_VALUE (pos, 8); @@ -2219,7 +2220,6 @@ _dbus_marshal_test (void) #endif char *s; DBusString t; - DBusObjectID obj_id, obj_id2; if (!_dbus_string_init (&str)) _dbus_assert_not_reached ("failed to init string"); @@ -2280,23 +2280,6 @@ _dbus_marshal_test (void) if (!(_dbus_demarshal_uint64 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == DBUS_UINT64_CONSTANT (0x123456789abc7))) _dbus_assert_not_reached ("demarshal failed"); #endif /* DBUS_HAVE_INT64 */ - - /* Marshal object IDs */ - dbus_object_id_set_server_bits (&obj_id, 0xfffe); - dbus_object_id_set_client_bits (&obj_id, 0xaacc); - dbus_object_id_set_instance_bits (&obj_id, 0x70f00f0f); - - if (!_dbus_marshal_object_id (&str, DBUS_BIG_ENDIAN, &obj_id)) - _dbus_assert_not_reached ("could not marshal object ID value"); - _dbus_demarshal_object_id (&str, DBUS_BIG_ENDIAN, pos, &pos, &obj_id2); - if (!dbus_object_id_equal (&obj_id, &obj_id2)) - _dbus_assert_not_reached ("demarshal failed"); - - if (!_dbus_marshal_object_id (&str, DBUS_LITTLE_ENDIAN, &obj_id)) - _dbus_assert_not_reached ("could not marshal object ID value"); - _dbus_demarshal_object_id (&str, DBUS_LITTLE_ENDIAN, pos, &pos, &obj_id2); - if (!dbus_object_id_equal (&obj_id, &obj_id2)) - _dbus_assert_not_reached ("demarshal failed"); /* Marshal strings */ tmp1 = "This is the dbus test string"; diff --git a/dbus/dbus-marshal.h b/dbus/dbus-marshal.h index af18876a..27ded007 100644 --- a/dbus/dbus-marshal.h +++ b/dbus/dbus-marshal.h @@ -29,7 +29,6 @@ #include #include #include -#include #ifndef PACKAGE #error "config.h not included here" @@ -154,15 +153,16 @@ void _dbus_marshal_set_uint64 (DBusString *str, dbus_uint64_t value); #endif /* DBUS_HAVE_INT64 */ -dbus_bool_t _dbus_marshal_set_string (DBusString *str, - int byte_order, - int offset, - const DBusString *value, - int len); -void _dbus_marshal_set_object_id (DBusString *str, - int byte_order, - int offset, - const DBusObjectID *value); +dbus_bool_t _dbus_marshal_set_string (DBusString *str, + int byte_order, + int offset, + const DBusString *value, + int len); +void _dbus_marshal_set_object_path (DBusString *str, + int byte_order, + int offset, + const char **path, + int path_len); dbus_bool_t _dbus_marshal_int32 (DBusString *str, int byte_order, @@ -214,9 +214,10 @@ dbus_bool_t _dbus_marshal_string_array (DBusString *str, int byte_order, const char **value, int len); -dbus_bool_t _dbus_marshal_object_id (DBusString *str, +dbus_bool_t _dbus_marshal_object_path (DBusString *str, int byte_order, - const DBusObjectID *value); + const char **path, + int path_len); double _dbus_demarshal_double (const DBusString *str, int byte_order, @@ -288,11 +289,12 @@ dbus_bool_t _dbus_demarshal_string_array (const DBusString *str, int *new_pos, char ***array, int *array_len); -void _dbus_demarshal_object_id (const DBusString *str, +dbus_bool_t _dbus_demarshal_object_path (const DBusString *str, int byte_order, int pos, int *new_pos, - DBusObjectID *value); + char ***path, + int *path_len); dbus_bool_t _dbus_marshal_get_arg_end_pos (const DBusString *str, int byte_order, diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c deleted file mode 100644 index e5a81315..00000000 --- a/dbus/dbus-object-registry.c +++ /dev/null @@ -1,1399 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-object-registry.c DBusObjectRegistry (internals of DBusConnection) - * - * Copyright (C) 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#include "dbus-object-registry.h" -#include "dbus-connection-internal.h" -#include "dbus-internals.h" -#include "dbus-hash.h" -#include "dbus-protocol.h" -#include - -/** - * @defgroup DBusObjectRegistry Map object IDs to implementations - * @ingroup DBusInternals - * @brief DBusObjectRegistry is used by DBusConnection to track object IDs - * - * Types and functions related to DBusObjectRegistry. These - * are all internal. - * - * @todo interface entries and signal connections are handled pretty - * much identically, with lots of duplicate code. Once we're sure - * they will always be the same, we could merge this code. - * - * @{ - */ - -typedef struct DBusObjectEntry DBusObjectEntry; -typedef struct DBusInterfaceEntry DBusInterfaceEntry; -typedef struct DBusSignalEntry DBusSignalEntry; - -#define DBUS_MAX_OBJECTS_PER_INTERFACE 65535 -struct DBusInterfaceEntry -{ - unsigned int n_objects : 16; /**< Number of objects with this interface */ - unsigned int n_allocated : 16; /**< Allocated size of objects array */ - dbus_uint16_t *objects; /**< Index of each object with the interface */ - char name[4]; /**< Name of interface (actually allocated larger) */ -}; - -#define DBUS_MAX_CONNECTIONS_PER_SIGNAL 65535 -struct DBusSignalEntry -{ - unsigned int n_connections : 16; /**< Number of connections to this signal */ - unsigned int n_allocated : 16; /**< Allocated size of objects array */ - dbus_uint16_t *connections; /**< Index of each object connected (can have dups for multiple - * connections) - */ - char name[4]; /**< Interface of signal, nul, then name of signal (actually allocated larger) */ -}; - - /* 14 bits for object index, 32K objects */ -#define DBUS_OBJECT_INDEX_BITS (14) -#define DBUS_OBJECT_INDEX_MASK (0x3fff) -#define DBUS_MAX_OBJECTS_PER_CONNECTION DBUS_OBJECT_INDEX_MASK -struct DBusObjectEntry -{ - unsigned int id_index : 14; /**< Index of this entry in the entries array */ - unsigned int id_times_used : 18; /**< Count of times entry has been used; avoids recycling IDs too often */ - - void *object_impl; /**< Pointer to application-supplied implementation */ - const DBusObjectVTable *vtable; /**< Virtual table for this object */ - DBusInterfaceEntry **interfaces; /**< NULL-terminated list of interfaces */ - DBusSignalEntry **signals; /**< Signal connections (contains dups, one each time we connect) */ -}; - -struct DBusObjectRegistry -{ - int refcount; - DBusConnection *connection; - - DBusObjectEntry *entries; - int n_entries_allocated; - int n_entries_used; - - DBusHashTable *interface_table; - - DBusHashTable *signal_table; -}; - -static void -free_interface_entry (void *entry) -{ - DBusInterfaceEntry *iface = entry; - - if (iface == NULL) /* DBusHashTable stupidity */ - return; - - dbus_free (iface->objects); - dbus_free (iface); -} - -static void -free_signal_entry (void *entry) -{ - DBusSignalEntry *signal = entry; - - if (signal == NULL) /* DBusHashTable stupidity */ - return; - - dbus_free (signal->connections); - dbus_free (signal); -} - -DBusObjectRegistry* -_dbus_object_registry_new (DBusConnection *connection) -{ - DBusObjectRegistry *registry; - DBusHashTable *interface_table; - DBusHashTable *signal_table; - - /* the connection passed in here isn't fully constructed, - * so don't do anything more than store a pointer to - * it - */ - - registry = NULL; - interface_table = NULL; - signal_table = NULL; - - registry = dbus_new0 (DBusObjectRegistry, 1); - if (registry == NULL) - goto oom; - - interface_table = _dbus_hash_table_new (DBUS_HASH_STRING, - NULL, free_interface_entry); - if (interface_table == NULL) - goto oom; - - signal_table = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS, - NULL, free_signal_entry); - if (signal_table == NULL) - goto oom; - - registry->refcount = 1; - registry->connection = connection; - registry->interface_table = interface_table; - registry->signal_table = signal_table; - - return registry; - - oom: - if (registry) - dbus_free (registry); - if (interface_table) - _dbus_hash_table_unref (interface_table); - if (signal_table) - _dbus_hash_table_unref (signal_table); - - return NULL; -} - -void -_dbus_object_registry_ref (DBusObjectRegistry *registry) -{ - _dbus_assert (registry->refcount > 0); - - registry->refcount += 1; -} - -void -_dbus_object_registry_unref (DBusObjectRegistry *registry) -{ - _dbus_assert (registry->refcount > 0); - - registry->refcount -= 1; - - if (registry->refcount == 0) - { - int i; - - _dbus_assert (registry->n_entries_used == 0); - _dbus_assert (_dbus_hash_table_get_n_entries (registry->interface_table) == 0); - _dbus_assert (_dbus_hash_table_get_n_entries (registry->signal_table) == 0); - - i = 0; - while (i < registry->n_entries_allocated) - { - if (registry->entries[i].interfaces) - dbus_free (registry->entries[i].interfaces); - if (registry->entries[i].signals) - dbus_free (registry->entries[i].signals); - ++i; - } - - _dbus_hash_table_unref (registry->interface_table); - _dbus_hash_table_unref (registry->signal_table); - dbus_free (registry->entries); - dbus_free (registry); - } -} - -#define ENTRY_TO_ID(entry) \ - (((dbus_uint32_t) (entry)->id_index) | \ - (((dbus_uint32_t)(entry)->id_times_used) << DBUS_OBJECT_INDEX_BITS)) - -#define ID_TO_INDEX(id) \ - (((dbus_uint32_t) (id)) & DBUS_OBJECT_INDEX_MASK) - -#define ID_TO_TIMES_USED(id) \ - (((dbus_uint32_t) (id)) >> DBUS_OBJECT_INDEX_BITS) - -static DBusObjectEntry* -validate_id (DBusObjectRegistry *registry, - const DBusObjectID *object_id) -{ - int idx; - int times_used; - dbus_uint32_t instance_bits; - - instance_bits = dbus_object_id_get_instance_bits (object_id); - - /* Verify that connection ID bits are the same */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - { - DBusObjectID tmp_id; - - _dbus_connection_init_id (registry->connection, - &tmp_id); - dbus_object_id_set_instance_bits (&tmp_id, instance_bits); - - if (!dbus_object_id_equal (&tmp_id, object_id)) - return NULL; - } - - idx = ID_TO_INDEX (instance_bits); - times_used = ID_TO_TIMES_USED (instance_bits); - - if (idx >= registry->n_entries_allocated) - return NULL; - if (registry->entries[idx].vtable == NULL) - return NULL; - if (registry->entries[idx].id_times_used != times_used) - return NULL; - _dbus_assert (registry->entries[idx].id_index == idx); - _dbus_assert (registry->n_entries_used > 0); - - return ®istry->entries[idx]; -} - -static void -id_from_entry (DBusObjectRegistry *registry, - DBusObjectID *object_id, - DBusObjectEntry *entry) -{ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_init_id (registry->connection, - object_id); -#ifdef DBUS_BUILD_TESTS - else - { - dbus_object_id_set_server_bits (object_id, 1); - dbus_object_id_set_client_bits (object_id, 2); - } -#endif - - _dbus_assert (dbus_object_id_get_server_bits (object_id) != 0); - _dbus_assert (dbus_object_id_get_client_bits (object_id) != 0); - - dbus_object_id_set_instance_bits (object_id, - ENTRY_TO_ID (entry)); - - _dbus_assert (dbus_object_id_get_instance_bits (object_id) != 0); -} - -static void -info_from_entry (DBusObjectRegistry *registry, - DBusObjectInfo *info, - DBusObjectEntry *entry) -{ - info->connection = registry->connection; - info->object_impl = entry->object_impl; - - id_from_entry (registry, &info->object_id, entry); -} - -static DBusInterfaceEntry* -lookup_interface (DBusObjectRegistry *registry, - const char *name, - dbus_bool_t create_if_not_found) -{ - DBusInterfaceEntry *entry; - int sz; - int len; - - entry = _dbus_hash_table_lookup_string (registry->interface_table, - name); - if (entry != NULL || !create_if_not_found) - return entry; - - _dbus_assert (create_if_not_found); - - len = strlen (name); - sz = _DBUS_STRUCT_OFFSET (DBusInterfaceEntry, name) + len + 1; - entry = dbus_malloc (sz); - if (entry == NULL) - return NULL; - entry->n_objects = 0; - entry->n_allocated = 0; - entry->objects = NULL; - memcpy (entry->name, name, len + 1); - - if (!_dbus_hash_table_insert_string (registry->interface_table, - entry->name, entry)) - { - dbus_free (entry); - return NULL; - } - - return entry; -} - -static void -delete_interface (DBusObjectRegistry *registry, - DBusInterfaceEntry *entry) -{ - _dbus_hash_table_remove_string (registry->interface_table, - entry->name); -} - -static dbus_bool_t -interface_entry_add_object (DBusInterfaceEntry *entry, - dbus_uint16_t object_index) -{ - if (entry->n_objects == entry->n_allocated) - { - unsigned int new_alloc; - dbus_uint16_t *new_objects; - - if (entry->n_allocated == 0) - new_alloc = 2; - else - new_alloc = entry->n_allocated * 2; - - /* Right now MAX_OBJECTS_PER_INTERFACE can't possibly be reached - * since the max number of objects _total_ is smaller, but the - * code is here for future robustness. - */ - - if (new_alloc > DBUS_MAX_OBJECTS_PER_INTERFACE) - new_alloc = DBUS_MAX_OBJECTS_PER_INTERFACE; - if (new_alloc == entry->n_allocated) - { - _dbus_warn ("Attempting to register another instance with interface %s, but max count %d reached\n", - entry->name, DBUS_MAX_OBJECTS_PER_INTERFACE); - return FALSE; - } - - new_objects = dbus_realloc (entry->objects, new_alloc * sizeof (dbus_uint16_t)); - if (new_objects == NULL) - return FALSE; - entry->objects = new_objects; - entry->n_allocated = new_alloc; - } - - _dbus_assert (entry->n_objects < entry->n_allocated); - - entry->objects[entry->n_objects] = object_index; - entry->n_objects += 1; - - return TRUE; -} - -static void -interface_entry_remove_object (DBusInterfaceEntry *entry, - dbus_uint16_t object_index) -{ - unsigned int i; - - i = 0; - while (i < entry->n_objects) - { - if (entry->objects[i] == object_index) - break; - ++i; - } - - if (i == entry->n_objects) - { - _dbus_assert_not_reached ("Tried to remove object from an interface that didn't list that object\n"); - return; - } - - memmove (&entry->objects[i], - &entry->objects[i+1], - (entry->n_objects - i - 1) * sizeof (entry->objects[0])); - entry->n_objects -= 1; -} - -static void -object_remove_from_interfaces (DBusObjectRegistry *registry, - DBusObjectEntry *entry) -{ - if (entry->interfaces != NULL) - { - int i; - - i = 0; - while (entry->interfaces[i] != NULL) - { - DBusInterfaceEntry *iface = entry->interfaces[i]; - - interface_entry_remove_object (iface, entry->id_index); - if (iface->n_objects == 0) - delete_interface (registry, iface); - ++i; - } - } -} - -static DBusSignalEntry* -lookup_signal (DBusObjectRegistry *registry, - const char *signal_interface, - const char *signal_name, - dbus_bool_t create_if_not_found) -{ - DBusSignalEntry *entry; - int sz; - 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. - */ - - 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); - - 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, buf, len_interface + len_name + 2); - - if (!_dbus_hash_table_insert_two_strings (registry->signal_table, - entry->name, entry)) - { - dbus_free (entry); - return NULL; - } - - return entry; -} - -static void -delete_signal (DBusObjectRegistry *registry, - DBusSignalEntry *entry) -{ - _dbus_hash_table_remove_two_strings (registry->signal_table, - entry->name); -} - -static dbus_bool_t -signal_entry_add_object (DBusSignalEntry *entry, - dbus_uint16_t object_index) -{ - if (entry->n_connections == entry->n_allocated) - { - unsigned int new_alloc; - dbus_uint16_t *new_objects; - - if (entry->n_allocated == 0) - new_alloc = 2; - else - new_alloc = entry->n_allocated * 2; - - /* Right now MAX_CONNECTIONS_PER_SIGNAL can't possibly be reached - * since the max number of objects _total_ is smaller, but the - * code is here for future robustness. - */ - - if (new_alloc > DBUS_MAX_CONNECTIONS_PER_SIGNAL) - new_alloc = DBUS_MAX_CONNECTIONS_PER_SIGNAL; - if (new_alloc == entry->n_allocated) - { - _dbus_warn ("Attempting to register another instance with signal %s, but max count %d reached\n", - entry->name, DBUS_MAX_CONNECTIONS_PER_SIGNAL); - return FALSE; - } - - new_objects = dbus_realloc (entry->connections, new_alloc * sizeof (dbus_uint16_t)); - if (new_objects == NULL) - return FALSE; - entry->connections = new_objects; - entry->n_allocated = new_alloc; - } - - _dbus_assert (entry->n_connections < entry->n_allocated); - - entry->connections[entry->n_connections] = object_index; - entry->n_connections += 1; - - return TRUE; -} - -static void -signal_entry_remove_object (DBusSignalEntry *entry, - dbus_uint16_t object_index) -{ - unsigned int i; - - i = 0; - while (i < entry->n_connections) - { - if (entry->connections[i] == object_index) - break; - ++i; - } - - if (i == entry->n_connections) - { - _dbus_assert_not_reached ("Tried to remove object from an signal that didn't list that object\n"); - return; - } - - memmove (&entry->connections[i], - &entry->connections[i+1], - (entry->n_connections - i - 1) * sizeof (entry->connections[0])); - entry->n_connections -= 1; -} - -static void -object_remove_from_signals (DBusObjectRegistry *registry, - DBusObjectEntry *entry) -{ - if (entry->signals != NULL) - { - int i; - - i = 0; - while (entry->signals[i] != NULL) - { - DBusSignalEntry *signal = entry->signals[i]; - - signal_entry_remove_object (signal, entry->id_index); - if (signal->n_connections == 0) - delete_signal (registry, signal); - ++i; - } - } -} - -/** - * Connect this object to the given signal, such that if a - * signal emission message is received with the given - * signal name, the message will be routed to the - * given object. - * - * Must be called with #DBusConnection lock held. - * - * @param registry the object registry - * @param object_id object that would like to see the signal - * @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) - { - _dbus_warn ("Tried to connect a nonexistent D-BUS object ID to signal \"%s\"\n", - signal_name); - - return FALSE; - } - - /* O(n) in number of connections unfortunately, but in practice I - * don't think it will matter. It's marginally a space-time - * tradeoff (save an n_signals field) but the NULL termination is - * just as large as an n_signals once we have even a single - * connection. - */ - i = 0; - if (entry->signals != NULL) - { - while (entry->signals[i] != NULL) - ++i; - } - - new_signals = dbus_realloc (entry->signals, - (i + 2) * sizeof (DBusSignalEntry*)); - - if (new_signals == NULL) - return FALSE; - - entry->signals = new_signals; - - signal = lookup_signal (registry, signal_interface, signal_name, TRUE); - if (signal == NULL) - goto oom; - - if (!signal_entry_add_object (signal, entry->id_index)) - goto oom; - - entry->signals[i] = signal; - ++i; - entry->signals[i] = NULL; - - return TRUE; - - oom: - if (signal && signal->n_connections == 0) - delete_signal (registry, signal); - - return FALSE; -} - -/** - * Reverses effects of _dbus_object_registry_disconnect_locked(). - * - * @param registry the object registry - * @param object_id object that would like to see the signal - * @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\"::\"%s\" from a nonexistent D-BUS object ID\n", - signal_interface, signal_name); - - return; - } - - signal = lookup_signal (registry, signal_interface, signal_name, FALSE); - if (signal == NULL) - { - _dbus_warn ("Tried to disconnect signal \"%s\"::\"%s\" but no such signal is connected\n", - signal_interface, signal_name); - return; - } - - signal_entry_remove_object (signal, entry->id_index); - - if (signal->n_connections == 0) - delete_signal (registry, signal); -} - -static DBusHandlerResult -handle_method_call_and_unlock (DBusObjectRegistry *registry, - DBusMessage *message) -{ - DBusInterfaceEntry *iface_entry; - DBusObjectEntry *object_entry; - DBusObjectInfo info; - const DBusObjectVTable *vtable; - - _dbus_assert (registry != NULL); - _dbus_assert (message != NULL); - - /* FIXME handle calls to an object ID instead of just an - * interface name - */ - - /* If the message isn't to a specific object ID, we send - * it to the first object that supports the given interface. - */ - iface_entry = lookup_interface (registry, - dbus_message_get_interface (message), - FALSE); - - if (iface_entry == NULL) - { -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - _dbus_assert (iface_entry->n_objects > 0); - _dbus_assert (iface_entry->objects != NULL); - - object_entry = ®istry->entries[iface_entry->objects[0]]; - - - /* Once we have an object entry, pass message to the object */ - - _dbus_assert (object_entry->vtable != NULL); - - info_from_entry (registry, &info, object_entry); - vtable = object_entry->vtable; - - /* Drop lock and invoke application code */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - (* vtable->message) (&info, message); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -typedef struct -{ - DBusObjectID id; -} ObjectEmitData; - -static DBusHandlerResult -handle_signal_and_unlock (DBusObjectRegistry *registry, - DBusMessage *message) -{ - DBusSignalEntry *signal_entry; - int i; - ObjectEmitData *objects; - int n_objects; - - _dbus_assert (registry != NULL); - _dbus_assert (message != NULL); - - signal_entry = lookup_signal (registry, - dbus_message_get_interface (message), - dbus_message_get_member (message), - FALSE); - - if (signal_entry == NULL) - { -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - _dbus_assert (signal_entry->n_connections > 0); - _dbus_assert (signal_entry->connections != NULL); - - /* make a copy for safety vs. reentrancy */ - - /* FIXME (?) if you disconnect a signal during (vs. before) - * emission, you still receive that signal. To fix this uses more - * memory because we don't have a per-connection object at the - * moment. You would have to introduce a connection object and - * refcount it and have a "disconnected" flag. This is more like - * GObject semantics but also maybe not important at this level (the - * GObject/Qt wrappers can mop it up). - */ - - n_objects = signal_entry->n_connections; - objects = dbus_new (ObjectEmitData, n_objects); - - if (objects == NULL) - { -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; - } - - i = 0; - while (i < signal_entry->n_connections) - { - DBusObjectEntry *object_entry; - int idx; - - idx = signal_entry->connections[i]; - - object_entry = ®istry->entries[idx]; - - _dbus_assert (object_entry->vtable != NULL); - - id_from_entry (registry, - &objects[i].id, - object_entry); - - ++i; - } - -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_ref_unlocked (registry->connection); - _dbus_object_registry_ref (registry); - dbus_message_ref (message); - - i = 0; - while (i < n_objects) - { - DBusObjectEntry *object_entry; - - /* If an object ID no longer exists, don't send the - * signal - */ - object_entry = validate_id (registry, &objects[i].id); - if (object_entry != NULL) - { - const DBusObjectVTable *vtable; - DBusObjectInfo info; - - info_from_entry (registry, &info, object_entry); - vtable = object_entry->vtable; - - /* Drop lock and invoke application code */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - (* vtable->message) (&info, message); - - /* Reacquire lock */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_lock (registry->connection); - } - ++i; - } - - dbus_message_unref (message); - _dbus_object_registry_unref (registry); -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unref_unlocked (registry->connection); - - dbus_free (objects); - - /* Drop lock a final time */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -/** - * Handle a message, passing it to any objects in the registry that - * should receive it. - * - * @todo handle messages to an object ID, not just those to - * an interface name. - * - * @param registry the object registry - * @param message the message to handle - * @returns what to do with the message next - */ -DBusHandlerResult -_dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, - DBusMessage *message) -{ - int type; - - _dbus_assert (registry != NULL); - _dbus_assert (message != NULL); - - type = dbus_message_get_type (message); - - switch (type) - { - case DBUS_MESSAGE_TYPE_METHOD_CALL: - return handle_method_call_and_unlock (registry, message); - case DBUS_MESSAGE_TYPE_SIGNAL: - return handle_signal_and_unlock (registry, message); - default: -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } -} - -dbus_bool_t -_dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, - const char **interfaces, - const DBusObjectVTable *vtable, - void *object_impl, - DBusObjectID *object_id) -{ - int idx; - int i; - DBusObjectInfo info; - - if (registry->n_entries_used == registry->n_entries_allocated) - { - DBusObjectEntry *new_entries; - int new_alloc; - - if (registry->n_entries_allocated == 0) - new_alloc = 16; - else - { - if (registry->n_entries_allocated == DBUS_MAX_OBJECTS_PER_CONNECTION) - { - _dbus_warn ("Attempting to register a new D-BUS object, but maximum object count of %d reached\n", - DBUS_MAX_OBJECTS_PER_CONNECTION); - goto out_0; - } - - new_alloc = registry->n_entries_allocated * 2; - if (new_alloc > DBUS_MAX_OBJECTS_PER_CONNECTION) - new_alloc = DBUS_MAX_OBJECTS_PER_CONNECTION; - } - - new_entries = dbus_realloc (registry->entries, - new_alloc * sizeof (DBusObjectEntry)); - - if (new_entries == NULL) - goto out_0; - - memset (&new_entries[registry->n_entries_allocated], - '\0', - sizeof (DBusObjectEntry) * (new_alloc - registry->n_entries_allocated)); - - registry->entries = new_entries; - registry->n_entries_allocated = new_alloc; - } - _dbus_assert (registry->n_entries_used < registry->n_entries_allocated); - - /* We linear search for an available entry. However, short-circuit - * the hopefully-common situation where we don't have a sparse - * array. - */ - if (registry->entries[registry->n_entries_used].vtable == NULL) - { - idx = registry->n_entries_used; - } - else - { - /* If we do have a sparse array, we try to get rid of it rather - * than using empty slots on the end, so we won't hit this case - * next time. - */ - - /* If index n_entries_used is occupied, then - * there is at least one entry outside of - * the range [0, n_entries_used). Thus, there is - * at least one blank entry inside that range. - */ - idx = 0; - while (idx < registry->n_entries_used) - { - if (registry->entries[idx].vtable == NULL) - break; - ++idx; - } - - _dbus_assert (idx < registry->n_entries_used); - } - - registry->entries[idx].id_index = idx; - /* Overflow is OK here, but zero isn't as it's a null ID */ - registry->entries[idx].id_times_used += 1; - if (registry->entries[idx].id_times_used == 0) - registry->entries[idx].id_times_used += 1; - - registry->entries[idx].vtable = vtable; - registry->entries[idx].object_impl = object_impl; - - registry->n_entries_used += 1; - - i = 0; - if (interfaces != NULL) - { - while (interfaces[i] != NULL) - ++i; - } - - if (i > 0) - { - DBusInterfaceEntry **new_interfaces; - - new_interfaces = - dbus_realloc (registry->entries[idx].interfaces, - (i + 1) * sizeof (DBusInterfaceEntry*)); - - if (new_interfaces == NULL) - { - /* maintain invariant that .interfaces array points to something - * valid in oom handler (entering this function it pointed to - * stale data but a valid malloc block) - */ - dbus_free (registry->entries[idx].interfaces); - registry->entries[idx].interfaces = NULL; - goto out_1; - } - - /* NULL-init so it's NULL-terminated and the OOM - * case can see how far we got - */ - while (i >= 0) - { - new_interfaces[i] = NULL; - --i; - } - - registry->entries[idx].interfaces = new_interfaces; - } - else - { - dbus_free (registry->entries[idx].interfaces); - registry->entries[idx].interfaces = NULL; - } - - /* Fill in interfaces */ - if (interfaces != NULL) - { - i = 0; - while (interfaces[i] != NULL) - { - DBusInterfaceEntry *iface; - - iface = lookup_interface (registry, interfaces[i], - TRUE); - if (iface == NULL) - goto out_1; - - if (!interface_entry_add_object (iface, idx)) - { - if (iface->n_objects == 0) - delete_interface (registry, iface); - goto out_1; - } - - registry->entries[idx].interfaces[i] = iface; - - ++i; - } - } - - info_from_entry (registry, &info, ®istry->entries[idx]); - if (object_id) - *object_id = info.object_id; - - /* Drop lock and invoke application code */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - (* vtable->registered) (&info); - - return TRUE; - - out_1: - registry->entries[idx].vtable = NULL; - registry->entries[idx].object_impl = NULL; - registry->n_entries_used -= 1; - - object_remove_from_interfaces (registry, - ®istry->entries[idx]); - - out_0: -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - return FALSE; -} - -void -_dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, - const DBusObjectID *object_id) -{ - DBusObjectInfo info; - DBusObjectEntry *entry; - const DBusObjectVTable *vtable; - - entry = validate_id (registry, object_id); - if (entry == NULL) - { - _dbus_warn ("Tried to unregister a nonexistent D-BUS object ID\n"); -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - return; - } - - object_remove_from_signals (registry, entry); - object_remove_from_interfaces (registry, entry); - - info_from_entry (registry, &info, entry); - vtable = entry->vtable; - entry->vtable = NULL; - entry->object_impl = NULL; - registry->n_entries_used -= 1; - - /* Drop lock and invoke application code */ -#ifdef DBUS_BUILD_TESTS - if (registry->connection) -#endif - _dbus_connection_unlock (registry->connection); - - (* vtable->unregistered) (&info); -} - - -void -_dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) -{ - int i; - - i = 0; - while (registry->n_entries_used > 0) - { - _dbus_assert (i < registry->n_entries_allocated); - if (registry->entries[i].vtable != NULL) - { - DBusObjectInfo info; - const DBusObjectVTable *vtable; - - object_remove_from_interfaces (registry, - ®istry->entries[i]); - - info_from_entry (registry, &info, ®istry->entries[i]); - vtable = registry->entries[i].vtable; - registry->entries[i].vtable = NULL; - registry->entries[i].object_impl = NULL; - registry->n_entries_used -= 1; - _dbus_assert (registry->n_entries_used >= 0); - - (* vtable->unregistered) (&info); - } - - ++i; - } - - _dbus_assert (registry->n_entries_used == 0); -} - -/** @} */ - -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include - -static void -noop_message_function (DBusObjectInfo *info, - DBusMessage *message) -{ - /* nothing */ -} - -static void -add_and_remove_objects (DBusObjectRegistry *registry) -{ -#define N_OBJECTS 73 - DBusObjectID ids[N_OBJECTS]; - const char *zero_interfaces[] = { NULL }; - const char *one_interface[] = { "org.freedesktop.Test.Blah", NULL }; - const char *three_interfaces[] = { "org.freedesktop.Test.Blah", - "org.freedesktop.Test.Baz", - "org.freedesktop.Test.Foo", - NULL }; - int i; - DBusMessage *message; - - i = 0; - while (i < N_OBJECTS) - { - DBusCallbackObject *callback; - const char **interfaces; - - callback = dbus_callback_object_new (noop_message_function, NULL, NULL); - if (callback == NULL) - goto out; - - interfaces = NULL; - switch (i % 3) - { - case 0: - interfaces = zero_interfaces; - break; - case 1: - interfaces = one_interface; - break; - case 2: - interfaces = three_interfaces; - break; - } - _dbus_assert (interfaces != NULL); - - if (!_dbus_object_registry_add_and_unlock (registry, - interfaces, - dbus_callback_object_vtable, - callback, - &ids[i])) - { - dbus_callback_object_unref (callback); - goto out; - } - - dbus_callback_object_unref (callback); - - ++i; - } - - i = 0; - while (i < N_OBJECTS) - { - if (i > (N_OBJECTS - 20) || (i % 3) == 0) - { - _dbus_object_registry_remove_and_unlock (registry, - &ids[i]); - dbus_object_id_set_null (&ids[i]); - } - - ++i; - } - - i = 0; - while (i < N_OBJECTS) - { - if (dbus_object_id_is_null (&ids[i])) - { - DBusCallbackObject *callback; - const char **interfaces; - - callback = dbus_callback_object_new (noop_message_function, NULL, NULL); - if (callback == NULL) - goto out; - - interfaces = NULL; - switch (i % 4) - { - case 0: - interfaces = NULL; - break; - case 1: - interfaces = zero_interfaces; - break; - case 2: - interfaces = one_interface; - break; - case 3: - interfaces = three_interfaces; - break; - } - - if (!_dbus_object_registry_add_and_unlock (registry, - interfaces, - dbus_callback_object_vtable, - callback, - &ids[i])) - { - dbus_callback_object_unref (callback); - goto out; - } - - dbus_callback_object_unref (callback); - } - - ++i; - } - - message = dbus_message_new_method_call ("org.freedesktop.Test.Foo", - "Bar", NULL); - if (message != NULL) - { - if (_dbus_object_registry_handle_and_unlock (registry, message) != - DBUS_HANDLER_RESULT_HANDLED) - _dbus_assert_not_reached ("message not handled\n"); - dbus_message_unref (message); - } - - message = dbus_message_new_method_call ("org.freedesktop.Test.Blah", - "Baz", NULL); - if (message != NULL) - { - if (_dbus_object_registry_handle_and_unlock (registry, message) != - DBUS_HANDLER_RESULT_HANDLED) - _dbus_assert_not_reached ("message not handled\n"); - dbus_message_unref (message); - } - - message = dbus_message_new_method_call ("org.freedesktop.Test.NotRegisteredIface", - "Boo", NULL); - if (message != NULL) - { - if (_dbus_object_registry_handle_and_unlock (registry, message) != - DBUS_HANDLER_RESULT_NOT_YET_HANDLED) - _dbus_assert_not_reached ("message handled but no handler was registered\n"); - dbus_message_unref (message); - } - - i = 0; - while (i < (N_OBJECTS - 30)) - { - _dbus_assert (!dbus_object_id_is_null (&ids[i])); - - _dbus_object_registry_remove_and_unlock (registry, - &ids[i]); - ++i; - } - - out: - /* unregister the rest this way, to test this function */ - _dbus_object_registry_free_all_unlocked (registry); -} - -static dbus_bool_t -object_registry_test_iteration (void *data) -{ - DBusObjectRegistry *registry; - - registry = _dbus_object_registry_new (NULL); - if (registry == NULL) - return TRUE; - - /* we do this twice since realloc behavior will differ each time, - * and the IDs will get recycled leading to slightly different - * codepaths - */ - add_and_remove_objects (registry); - add_and_remove_objects (registry); - - _dbus_object_registry_unref (registry); - - return TRUE; -} - -/** - * @ingroup DBusObjectRegistry - * Unit test for DBusObjectRegistry - * @returns #TRUE on success. - */ -dbus_bool_t -_dbus_object_registry_test (void) -{ - _dbus_test_oom_handling ("object registry", - object_registry_test_iteration, - NULL); - - return TRUE; -} - -#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-object-registry.h b/dbus/dbus-object-registry.h deleted file mode 100644 index 29c92b9c..00000000 --- a/dbus/dbus-object-registry.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-object-registry.h DBusObjectRegistry (internals of DBusConnection) - * - * Copyright (C) 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#ifndef DBUS_OBJECT_REGISTRY_H -#define DBUS_OBJECT_REGISTRY_H - -#include - -DBUS_BEGIN_DECLS; - -typedef struct DBusObjectRegistry DBusObjectRegistry; - -DBusObjectRegistry* _dbus_object_registry_new (DBusConnection *connection); -void _dbus_object_registry_ref (DBusObjectRegistry *registry); -void _dbus_object_registry_unref (DBusObjectRegistry *registry); - -dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, - const char **interfaces, - const DBusObjectVTable *vtable, - void *object_impl, - DBusObjectID *object_id); -void _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, - const DBusObjectID *object_id); -DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, - DBusMessage *message); -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_interface, - const char *signal_name); -void _dbus_object_registry_disconnect_locked (DBusObjectRegistry *registry, - const DBusObjectID *object_id, - const char *signal_interface, - const char *signal_name); - -DBUS_END_DECLS; - -#endif /* DBUS_OBJECT_REGISTRY_H */ diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 7f7e6011..31724b7b 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -42,7 +42,7 @@ typedef struct DBusObjectSubtree DBusObjectSubtree; DBusObjectSubtree* _dbus_object_subtree_new (const char **path, - const DBusObjectTreeVTable *vtable, + const DBusObjectPathVTable *vtable, void *user_data); void _dbus_object_subtree_ref (DBusObjectSubtree *subtree); void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); @@ -66,7 +66,7 @@ struct DBusObjectSubtree int refcount; char **path; int n_path_elements; - DBusObjectTreeVTable vtable; + DBusObjectPathVTable vtable; void *user_data; }; @@ -299,7 +299,7 @@ check_overlap (DBusObjectTree *tree, dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, const char **path, - const DBusObjectTreeVTable *vtable, + const DBusObjectPathVTable *vtable, void *user_data) { DBusObjectSubtree *subtree; @@ -381,10 +381,27 @@ _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) +{ + + +} + /** * Tries to dispatch a message by directing it to the object tree * node listed in the message header, if any. * + * @todo implement + * * @param tree the global object tree * @param message the message to dispatch * @returns whether message was handled successfully @@ -399,7 +416,7 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, DBusObjectSubtree* _dbus_object_subtree_new (const char **path, - const DBusObjectTreeVTable *vtable, + const DBusObjectPathVTable *vtable, void *user_data) { DBusObjectSubtree *subtree; @@ -476,7 +493,7 @@ test_subtree_cmp (const char **path1, DBusObjectSubtree *subtree1; DBusObjectSubtree *subtree2; dbus_bool_t retval; - DBusObjectTreeVTable vtable; + DBusObjectPathVTable vtable; _DBUS_ZERO (vtable); diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h index 06033333..5d44bbe2 100644 --- a/dbus/dbus-object-tree.h +++ b/dbus/dbus-object-tree.h @@ -35,12 +35,13 @@ void _dbus_object_tree_unref (DBusObjectTree *tree); dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, const char **path, - const DBusObjectTreeVTable *vtable, + const DBusObjectPathVTable *vtable, void *user_data); void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, const char **path); DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, DBusMessage *message); +void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree); DBUS_END_DECLS; diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c deleted file mode 100644 index 5582f94a..00000000 --- a/dbus/dbus-object.c +++ /dev/null @@ -1,349 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-object.c Objects - * - * Copyright (C) 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include "dbus-internals.h" -#include "dbus-object.h" - -/** - * @defgroup DBusCallbackObjectInternals DBusCallbackObject implementation details - * @ingroup DBusInternals - * @brief DBusCallbackObject private implementation details. - * - * The guts of DBusCallbackObject and its methods. - * - * @{ - */ - -_DBUS_DEFINE_GLOBAL_LOCK (callback_object); - -/** - * @brief Internals of DBusCallbackObject - * - * Object that can send and receive messages. - */ -struct DBusCallbackObject -{ - DBusAtomic refcount; /**< reference count */ - DBusObjectMessageFunction function; /**< callback function */ - void *user_data; /**< user data for function */ - DBusFreeFunction free_user_data; /**< free the user data */ -}; - -static void -callback_object_registered (DBusObjectInfo *info) -{ - DBusCallbackObject *callback = info->object_impl; - - dbus_callback_object_ref (callback); -} - -static void -callback_object_unregistered (DBusObjectInfo *info) -{ - DBusCallbackObject *callback = info->object_impl; - - dbus_callback_object_unref (callback); -} - -static void -callback_object_message (DBusObjectInfo *info, - DBusMessage *message) -{ - DBusCallbackObject *callback = info->object_impl; - - if (callback->function) - (* callback->function) (info, message); -} - -/** @} */ - -/** - * @defgroup DBusObject DBusObjectInfo, DBusObjectVTable, DBusCallbackObject - * @ingroup DBus - * @brief support for object instances - * - * Behind each DBusConnection are object instances. An object instance - * may be a GObject (using GLib), a QObject (using Qt), a built-in - * object type called DBusCallbackObject, or any other representation - * of an object; it's even permissible to have an object that's simply - * an integer value or a pointer to a struct. - * - * Objects are registered with one or more DBusConnection. Registered - * objects receive an object ID, represented by the DBusObjectID type. - * Object IDs can be passed over a DBusConnection and used by the - * remote application to refer to objects. Remote applications can - * also refer to objects by dynamically locating objects that support - * a particular interface. - * - * To define an object, you simply provide three callbacks: one to be - * called when the object is registered with a new connection, one - * to be called when the object is unregistered, and one to be called - * when the object receives a message from the peer on the other end - * of the DBusConnection. The three callbacks are specified in a - * DBusObjectVTable struct. - * - * The DBusObjectInfo struct is used to pass the object pointer - * (object_impl), connection, and object ID to each of the callbacks - * in the virtual table. This struct should be treated as read-only. - * - * DBusCallbackObject is provided for convenience as a way to - * implement an object quickly by writing only one callback function, - * the callback that processes messages. To use DBusCallbackObject, - * simply create one, then call dbus_connection_register_object() - * passing in the provided DBusObjectVTable - * dbus_callback_object_vtable. This is the simplest possible object; - * it simply contains a function to be called whenever a message is - * received. - * - * The DBusCallbackObject will be strong-referenced by the - * DBusConnection, so may be unreferenced once it's registered, and - * will go away either on unregistration or when the connection is - * freed. - * - * One DBusCallbackObject may be registered with any number of - * DBusConnection. - * - * @{ - */ - -/** - * @typedef DBusCallbackObject - * - * Opaque data type representing a callback object. - */ - -static const DBusObjectVTable callback_object_vtable = { - callback_object_registered, - callback_object_unregistered, - callback_object_message, - NULL, NULL, NULL -}; - -/** - * Virtual table for a DBusCallbackObject, used to register the - * callback object with dbus_connection_register_object(). - */ -const DBusObjectVTable* dbus_callback_object_vtable = &callback_object_vtable; - -/** - * Creates a new callback object. The callback function - * may be #NULL for a no-op callback or a callback to - * be assigned a function later. - * - * Use dbus_connection_register_object() along with - * dbus_callback_object_vtable to register the callback object with - * one or more connections. Each connection will add a reference to - * the callback object, so once it's registered it may be unreferenced - * with dbus_callback_object_unref(). - * - * @param function function to call to handle a message - * @param user_data data to pass to the function - * @param free_user_data function to call to free the user data - * @returns a new DBusCallbackObject or #NULL if no memory. - */ -DBusCallbackObject* -dbus_callback_object_new (DBusObjectMessageFunction function, - void *user_data, - DBusFreeFunction free_user_data) -{ - DBusCallbackObject *callback; - - callback = dbus_new0 (DBusCallbackObject, 1); - if (callback == NULL) - return NULL; - - callback->refcount.value = 1; - callback->function = function; - callback->user_data = user_data; - callback->free_user_data = free_user_data; - - return callback; -} - -/** - * Increments the reference count on a callback object. - * - * @param callback the callback - */ -void -dbus_callback_object_ref (DBusCallbackObject *callback) -{ - _dbus_return_if_fail (callback != NULL); - - _dbus_atomic_inc (&callback->refcount); -} - - -/** - * Decrements the reference count on a callback object, - * freeing the callback if the count reaches 0. - * - * @param callback the callback - */ -void -dbus_callback_object_unref (DBusCallbackObject *callback) -{ - dbus_bool_t last_unref; - - _dbus_return_if_fail (callback != NULL); - - last_unref = (_dbus_atomic_dec (&callback->refcount) == 1); - - if (last_unref) - { - if (callback->free_user_data) - (* callback->free_user_data) (callback->user_data); - - dbus_free (callback); - } -} - -/** - * Gets the user data for the callback. - * - * @param callback the callback - * @returns the user data - */ -void* -dbus_callback_object_get_data (DBusCallbackObject *callback) -{ - void* user_data; - - _dbus_return_val_if_fail (callback != NULL, NULL); - - _DBUS_LOCK (callback_object); - user_data = callback->user_data; - _DBUS_UNLOCK (callback_object); - return user_data; -} - - -/** - * Sets the user data for the callback. Frees any previously-existing - * user data with the previous free_user_data function. - * - * @param callback the callback - * @param user_data the user data - * @param free_user_data free function for the data - */ -void -dbus_callback_object_set_data (DBusCallbackObject *callback, - void *user_data, - DBusFreeFunction free_user_data) -{ - DBusFreeFunction old_free_func; - void *old_user_data; - - _dbus_return_if_fail (callback != NULL); - - _DBUS_LOCK (callback_object); - old_free_func = callback->free_user_data; - old_user_data = callback->user_data; - - callback->user_data = user_data; - callback->free_user_data = free_user_data; - _DBUS_UNLOCK (callback_object); - - if (old_free_func) - (* old_free_func) (old_user_data); -} - -/** - * Sets the function to be used to handle messages to the - * callback object. - * - * @todo the thread locking on DBusCallbackObject is hosed; in this - * function in particular it's a joke since we don't take the same - * lock when _calling_ the callback function. - * - * @param callback the callback - * @param function the function - */ -void -dbus_callback_object_set_function (DBusCallbackObject *callback, - DBusObjectMessageFunction function) -{ - _dbus_return_if_fail (callback != NULL); - - _DBUS_LOCK (callback_object); - callback->function = function; - _DBUS_UNLOCK (callback_object); -} - -/** @} */ - -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include - -static void -test_message_function (DBusObjectInfo *info, - DBusMessage *message) -{ - /* nothing */ -} - -static void -free_test_data (void *data) -{ - /* does nothing */ -} - -/** - * @ingroup DBusCallbackObjectInternals - * Unit test for DBusCallbackObject. - * - * @returns #TRUE on success. - */ -dbus_bool_t -_dbus_object_test (void) -{ - DBusCallbackObject *callback; - -#define TEST_DATA ((void*) 0xcafebabe) - - callback = dbus_callback_object_new (test_message_function, - TEST_DATA, - free_test_data); - - _dbus_assert (callback != NULL); - _dbus_assert (callback->function == test_message_function); - - if (dbus_callback_object_get_data (callback) != TEST_DATA) - _dbus_assert_not_reached ("got wrong data"); - - dbus_callback_object_set_data (callback, NULL, NULL); - if (dbus_callback_object_get_data (callback) != NULL) - _dbus_assert_not_reached ("got wrong data after set"); - - dbus_callback_object_set_function (callback, NULL); - _dbus_assert (callback->function == NULL); - - dbus_callback_object_ref (callback); - dbus_callback_object_unref (callback); - dbus_callback_object_unref (callback); - - return TRUE; -} -#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h deleted file mode 100644 index 23c12d15..00000000 --- a/dbus/dbus-object.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-object.h Objects - * - * Copyright (C) 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) -#error "Only can be included directly, this file may disappear or change contents." -#endif - -#ifndef DBUS_OBJECT_H -#define DBUS_OBJECT_H - -#include -#include -#include -#include - -DBUS_BEGIN_DECLS; - -typedef struct DBusConnection DBusConnection; -typedef struct DBusObjectVTable DBusObjectVTable; -typedef struct DBusObjectInfo DBusObjectInfo; -typedef struct DBusCallbackObject DBusCallbackObject; - -typedef enum -{ - DBUS_HANDLER_RESULT_HANDLED, /**< Remove this message, no further processing. */ - DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Run any additional handlers that are interested in this message. */ - DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory to handle this message. */ -} DBusHandlerResult; - -struct DBusObjectInfo -{ - void *object_impl; /**< Object implementation pointer provided by app */ - DBusObjectID object_id; /**< Object ID */ - DBusConnection *connection; /**< The connection object ID is for */ - void *dbus_internal_pad1; /**< Padding, do not use */ - void *dbus_internal_pad2; /**< Padding, do not use */ -}; - -typedef void (* DBusObjectRegisteredFunction) (DBusObjectInfo *info); -typedef void (* DBusObjectUnregisteredFunction) (DBusObjectInfo *info); -typedef void (* DBusObjectMessageFunction) (DBusObjectInfo *info, - DBusMessage *message); - -struct DBusObjectVTable -{ - DBusObjectRegisteredFunction registered; - DBusObjectUnregisteredFunction unregistered; - DBusObjectMessageFunction message; - void (* dbus_internal_pad1) (void *); - void (* dbus_internal_pad2) (void *); - void (* dbus_internal_pad3) (void *); -}; - -extern const DBusObjectVTable *dbus_callback_object_vtable; - -DBusCallbackObject* dbus_callback_object_new (DBusObjectMessageFunction function, - void *user_data, - DBusFreeFunction free_user_data); -void dbus_callback_object_ref (DBusCallbackObject *callback); -void dbus_callback_object_unref (DBusCallbackObject *callback); -void* dbus_callback_object_get_data (DBusCallbackObject *callback); -void dbus_callback_object_set_data (DBusCallbackObject *callback, - void *data, - DBusFreeFunction free_user_data); -void dbus_callback_object_set_function (DBusCallbackObject *callback, - DBusObjectMessageFunction function); - - -DBUS_END_DECLS; - -#endif /* DBUS_OBJECT_H */ diff --git a/dbus/dbus-objectid.c b/dbus/dbus-objectid.c deleted file mode 100644 index f2b27b61..00000000 --- a/dbus/dbus-objectid.c +++ /dev/null @@ -1,470 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-objectid.c DBusObjectID type - * - * Copyright (C) 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "dbus-objectid.h" -#include "dbus-internals.h" - -#ifdef DBUS_HAVE_INT64 -#define VALUE(objid) ((objid)->dbus_do_not_use_dummy1) -#define SERVER_MASK DBUS_UINT64_CONSTANT (0xffff000000000000) -#define CLIENT_MASK DBUS_UINT64_CONSTANT (0x0000ffff00000000) -#define IS_SERVER_MASK DBUS_UINT64_CONSTANT (0x0000000080000000) -#define INSTANCE_MASK DBUS_UINT64_CONSTANT (0x000000007fffffff) -#define SERVER_BITS(objid) ((dbus_uint16_t) (VALUE (obj_id) >> 48)) -#define CLIENT_BITS(objid) ((dbus_uint16_t) ((VALUE (obj_id) & CLIENT_MASK) >> 32)) -#define IS_SERVER_BIT(objid) ((VALUE (obj_id) & IS_SERVER_MASK) != 0) -#define INSTANCE_BITS(objid) ((dbus_uint32_t) (VALUE (obj_id) & INSTANCE_MASK)) -#else -/* We care about the exact packing since in dbus-marshal.c we - * just use the DBusObjectID struct as-is. - */ -#ifdef WORDS_BIGENDIAN -#define HIGH_VALUE(objid) ((objid)->dbus_do_not_use_dummy2) -#define LOW_VALUE(objid) ((objid)->dbus_do_not_use_dummy3) -#else -#define HIGH_VALUE(objid) ((objid)->dbus_do_not_use_dummy3) -#define LOW_VALUE(objid) ((objid)->dbus_do_not_use_dummy2) -#endif -#define SERVER_MASK (0xffff0000) -#define CLIENT_MASK (0x0000ffff) -#define IS_SERVER_MASK (0x80000000) -#define INSTANCE_MASK (0x7fffffff) -#define SERVER_BITS(objid) ((HIGH_VALUE (objid) & SERVER_MASK) >> 16) -#define CLIENT_BITS(objid) (HIGH_VALUE (objid) & CLIENT_MASK) -#define IS_SERVER_BIT(objid) ((LOW_VALUE (objid) & IS_SERVER_MASK) != 0) -#define INSTANCE_BITS(objid) (LOW_VALUE (objid) & INSTANCE_MASK) -#endif - -/** - * @defgroup DBusObjectID object IDs - * @ingroup DBusObjectID - * @brief object ID datatype - * - * Value type representing an object ID, i.e. an object in the remote - * application that can be communicated with. - * - * An object ID has three parts. 16 bits are provided by the server - * side of a connection, and used for the high 16 bits of all object - * IDs created by the client. 16 bits are provided by the client side - * and used as the next 16 bits of all object IDs created by the - * client. The next single bit is 1 if the object ID represents an - * object on the server side of the connection and 0 otherwise. Then - * 31 bits are provided by the side creating an object instance and - * differ for each instance created (each app should make a best - * effort to avoid recycling the instance values). - * - * 0 is an invalid value for the server bits, the client bits, - * and the object instance bits. An object ID is the null ID - * if all 64 bits are 0. - * - * @{ - */ - -/** - * Checks whether two object IDs have the same value. - * - * @param a the first object ID - * @param b the second object ID - * @returns #TRUE if they are equal - */ -dbus_bool_t -dbus_object_id_equal (const DBusObjectID *a, - const DBusObjectID *b) -{ -#ifdef DBUS_HAVE_INT64 - return VALUE (a) == VALUE (b); -#else - return LOW_VALUE (a) == LOW_VALUE (b) && HIGH_VALUE (a) == HIGH_VALUE (b); -#endif -} - -/** - * Compares two object IDs, appropriate for - * qsort(). Higher/lower IDs have no significance, - * but the comparison can be used for data structures - * that require ordering. - * - * @param a the first object ID - * @param b the second object ID - * @returns -1, 0, 1 as with strcmp() - */ -int -dbus_object_id_compare (const DBusObjectID *a, - const DBusObjectID *b) -{ -#ifdef DBUS_HAVE_INT64 - if (VALUE (a) > VALUE (b)) - return 1; - else if (VALUE (a) < VALUE (b)) - return -1; - else - return 0; -#else - if (HIGH_VALUE (a) > HIGH_VALUE (b)) - return 1; - else if (HIGH_VALUE (a) < HIGH_VALUE (b)) - return -1; - else if (LOW_VALUE (a) > LOW_VALUE (b)) - return 1; - else if (LOW_VALUE (a) < LOW_VALUE (b)) - return -1; - else - return 0; -#endif -} - - -/** - * An object ID contains 64 bits of data. This function - * returns the 16 bits that were provided by the server - * side of the connection. - * - * @param obj_id the object ID - * @returns the server bits of the ID - * - */ -dbus_uint16_t -dbus_object_id_get_server_bits (const DBusObjectID *obj_id) -{ - return SERVER_BITS (obj_id); -} - -/** - * An object ID contains 64 bits of data. This function - * returns the 16 bits that were provided by the client - * side of the connection. - * - * @param obj_id the object ID - * @returns the client bits of the ID - * - */ -dbus_uint16_t -dbus_object_id_get_client_bits (const DBusObjectID *obj_id) -{ - return CLIENT_BITS (obj_id); -} - -/** - * An object ID contains 64 bits of data. This function - * returns the bit flagging whether the object ID comes - * from the client or the server side of the connection. - * - * There is no secure guarantee that the bit is accurate; - * object ID values are simply conventional, to make - * collisions relatively unlikely. - * - * @param obj_id the object ID - * @returns the server-side bit of the ID - * - */ -dbus_bool_t -dbus_object_id_get_is_server_bit (const DBusObjectID *obj_id) -{ - return IS_SERVER_BIT (obj_id); -} - -/** - * An object ID contains 64 bits of data. This function - * returns the 31 bits that identify the object instance. - * - * @param obj_id the object ID - * @returns the instance bits of the ID - * - */ -dbus_uint32_t -dbus_object_id_get_instance_bits (const DBusObjectID *obj_id) -{ - return INSTANCE_BITS (obj_id); -} - -/** - * An object ID contains 64 bits of data. This function sets the 16 - * bits provided by the server side of a connection. - * - * @param obj_id the object ID - * @param value the new value of the server bits - * - */ -void -dbus_object_id_set_server_bits (DBusObjectID *obj_id, - dbus_uint16_t value) -{ -#ifdef DBUS_HAVE_INT64 - VALUE (obj_id) &= ~ SERVER_MASK; - VALUE (obj_id) |= ((dbus_uint64_t) value) << 48; -#else - HIGH_VALUE (obj_id) &= ~ SERVER_MASK; - HIGH_VALUE (obj_id) |= ((dbus_uint32_t) value) << 16; -#endif -} - -/** - * An object ID contains 64 bits of data. This function sets the 16 - * bits provided by the client side of a connection. - * - * @param obj_id the object ID - * @param value the new value of the client bits - * - */ -void -dbus_object_id_set_client_bits (DBusObjectID *obj_id, - dbus_uint16_t value) -{ -#ifdef DBUS_HAVE_INT64 - VALUE (obj_id) &= ~ CLIENT_MASK; - VALUE (obj_id) |= ((dbus_uint64_t) value) << 32; -#else - HIGH_VALUE (obj_id) &= ~ CLIENT_MASK; - HIGH_VALUE (obj_id) |= (dbus_uint32_t) value; -#endif -} - -/** - * An object ID contains 64 bits of data. This function sets the - * single bit that flags an instance as server-side or client-side. - * - * @param obj_id the object ID - * @param value the new value of the server-side bit - * - */ -void -dbus_object_id_set_is_server_bit (DBusObjectID *obj_id, - dbus_bool_t value) -{ -#ifdef DBUS_HAVE_INT64 - if (value) - VALUE (obj_id) |= IS_SERVER_MASK; - else - VALUE (obj_id) &= ~ IS_SERVER_MASK; -#else - if (value) - LOW_VALUE (obj_id) |= IS_SERVER_MASK; - else - LOW_VALUE (obj_id) &= ~ IS_SERVER_MASK; -#endif -} - -/** - * An object ID contains 64 bits of data. This function sets the 31 - * bits identifying the object instance. - * - * @param obj_id the object ID - * @param value the new value of the instance bits - * - */ -void -dbus_object_id_set_instance_bits (DBusObjectID *obj_id, - dbus_uint32_t value) -{ -#ifdef DBUS_HAVE_INT64 - VALUE (obj_id) &= ~ INSTANCE_MASK; - VALUE (obj_id) |= (dbus_uint64_t) value; -#else - LOW_VALUE (obj_id) &= ~ INSTANCE_MASK; - LOW_VALUE (obj_id) |= (dbus_uint32_t) value; -#endif -} - -/** - * Set the object ID to an invalid value that cannot - * correspond to a valid object. - * - * @param obj_id the object ID - */ -void -dbus_object_id_set_null (DBusObjectID *obj_id) -{ - memset (obj_id, '\0', sizeof (DBusObjectID)); -} - -/** - * Check whether the object ID is set to a null value - * - * @param obj_id the object ID - * @returns #TRUE if null - */ -dbus_bool_t -dbus_object_id_is_null (const DBusObjectID *obj_id) -{ -#ifdef DBUS_HAVE_INT64 - return VALUE (obj_id) == 0; -#else - return HIGH_VALUE (obj_id) == 0 && LOW_VALUE (obj_id) == 0; -#endif -} - -#ifdef DBUS_HAVE_INT64 -/** - * An object ID contains 64 bits of data. This function - * returns all of them as a 64-bit integer. - * - * Use this function only if you are willing to limit portability to - * compilers with a 64-bit type (this includes C99 compilers and - * almost all other compilers). - * - * This function only exists if DBUS_HAVE_INT64 is defined. - * - * @param obj_id the object ID - * @returns the object ID as a 64-bit integer. - */ -dbus_uint64_t -dbus_object_id_get_as_integer (const DBusObjectID *obj_id) -{ - return VALUE (obj_id); -} - -/** - * An object ID contains 64 bits of data. This function sets all of - * them as a 64-bit integer. - * - * Use this function only if you are willing to limit portability to - * compilers with a 64-bit type (this includes C99 compilers and - * almost all other compilers). - * - * This function only exists if #DBUS_HAVE_INT64 is defined. - * - * @param obj_id the object ID - * @param value the new value of the object ID - */ -void -dbus_object_id_set_as_integer (DBusObjectID *obj_id, - dbus_uint64_t value) -{ - VALUE (obj_id) = value; -} -#endif /* DBUS_HAVE_INT64 */ - -/** @} */ - -#ifdef DBUS_BUILD_TESTS -#include "dbus-test.h" -#include - -/** - * Test for object ID routines. - * - * @returns #TRUE on success - */ -dbus_bool_t -_dbus_object_id_test (void) -{ - DBusObjectID tmp; - DBusObjectID tmp2; - - /* Check basic get/set */ - - dbus_object_id_set_server_bits (&tmp, 340); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); - - dbus_object_id_set_client_bits (&tmp, 1492); - _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); - - dbus_object_id_set_is_server_bit (&tmp, TRUE); - _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); - _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); - - dbus_object_id_set_instance_bits (&tmp, 2001); - _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340); - _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); - _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == 2001); - - /* check equality check */ - tmp2 = tmp; - _dbus_assert (dbus_object_id_equal (&tmp, &tmp2)); - - /* check get/set as integer */ -#ifdef DBUS_HAVE_INT64 - _dbus_assert (dbus_object_id_get_as_integer (&tmp) == - ((DBUS_UINT64_CONSTANT (340) << 48) | - (DBUS_UINT64_CONSTANT (1492) << 32) | - (DBUS_UINT64_CONSTANT (1) << 31) | - (DBUS_UINT64_CONSTANT (2001)))); - - dbus_object_id_set_as_integer (&tmp, _DBUS_UINT64_MAX); - _dbus_assert (dbus_object_id_get_as_integer (&tmp) == - _DBUS_UINT64_MAX); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == - 0xffff); - _dbus_assert (dbus_object_id_get_client_bits (&tmp) == - 0xffff); - _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == - TRUE); - _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == - 0x7fffffff); - - dbus_object_id_set_as_integer (&tmp, 1); - dbus_object_id_set_as_integer (&tmp2, 2); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); - dbus_object_id_set_as_integer (&tmp2, 0); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); - dbus_object_id_set_as_integer (&tmp2, 1); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); -#endif - - /* Check comparison */ - tmp2 = tmp; - - dbus_object_id_set_server_bits (&tmp, 1); - dbus_object_id_set_server_bits (&tmp2, 2); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); - dbus_object_id_set_server_bits (&tmp2, 0); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); - dbus_object_id_set_server_bits (&tmp2, 1); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); - - dbus_object_id_set_client_bits (&tmp, 1); - - dbus_object_id_set_client_bits (&tmp2, 2); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1); - dbus_object_id_set_client_bits (&tmp2, 0); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1); - dbus_object_id_set_client_bits (&tmp2, 1); - _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0); - - /* Check get/set again with high-limit numbers */ - - dbus_object_id_set_server_bits (&tmp, 0xf0f0); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); - - dbus_object_id_set_client_bits (&tmp, 0xf00f); - _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); - - dbus_object_id_set_is_server_bit (&tmp, TRUE); - _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); - _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); - - dbus_object_id_set_instance_bits (&tmp, 0x7fffffff); - _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f); - _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0); - _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE); - _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == 0x7fffffff); - - return TRUE; -} - -#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-objectid.h b/dbus/dbus-objectid.h deleted file mode 100644 index 9539f9be..00000000 --- a/dbus/dbus-objectid.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-objectid.h DBusObjectID type - * - * Copyright (C) 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) -#error "Only can be included directly, this file may disappear or change contents." -#endif - -#ifndef DBUS_OBJECTID_H -#define DBUS_OBJECTID_H - -#include -#include - -DBUS_BEGIN_DECLS; - -typedef struct DBusObjectID DBusObjectID; - -struct DBusObjectID -{ -#ifdef DBUS_HAVE_INT64 - dbus_uint64_t dbus_do_not_use_dummy1; -#else - dbus_uint32_t dbus_do_not_use_dummy2; - dbus_uint32_t dbus_do_not_use_dummy3; -#endif -}; - -dbus_bool_t dbus_object_id_equal (const DBusObjectID *a, - const DBusObjectID *b); -int dbus_object_id_compare (const DBusObjectID *a, - const DBusObjectID *b); -dbus_uint16_t dbus_object_id_get_server_bits (const DBusObjectID *obj_id); -dbus_uint16_t dbus_object_id_get_client_bits (const DBusObjectID *obj_id); -dbus_uint32_t dbus_object_id_get_connection_bits (const DBusObjectID *obj_id); -dbus_bool_t dbus_object_id_get_is_server_bit (const DBusObjectID *obj_id); -dbus_uint32_t dbus_object_id_get_instance_bits (const DBusObjectID *obj_id); -void dbus_object_id_set_server_bits (DBusObjectID *obj_id, - dbus_uint16_t value); -void dbus_object_id_set_client_bits (DBusObjectID *obj_id, - dbus_uint16_t value); -void dbus_object_id_set_is_server_bit (DBusObjectID *obj_id, - dbus_bool_t value); -void dbus_object_id_set_instance_bits (DBusObjectID *obj_id, - dbus_uint32_t value); -void dbus_object_id_set_null (DBusObjectID *obj_id); -dbus_bool_t dbus_object_id_is_null (const DBusObjectID *obj_id); - -#ifdef DBUS_HAVE_INT64 -dbus_uint64_t dbus_object_id_get_as_integer (const DBusObjectID *obj_id); -void dbus_object_id_set_as_integer (DBusObjectID *obj_id, - dbus_uint64_t value); -#endif - -DBUS_END_DECLS; - -#endif /* DBUS_OBJECTID_H */ diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 21c06a76..a23d7466 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -53,9 +53,9 @@ extern "C" { #define DBUS_TYPE_NAMED 10 #define DBUS_TYPE_ARRAY 11 #define DBUS_TYPE_DICT 12 -#define DBUS_TYPE_OBJECT_ID 13 +#define DBUS_TYPE_OBJECT_PATH 13 -#define DBUS_TYPE_LAST DBUS_TYPE_OBJECT_ID +#define DBUS_TYPE_LAST DBUS_TYPE_OBJECT_PATH /* Max length in bytes of a service or interface or member name */ #define DBUS_MAXIMUM_NAME_LENGTH 256 diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 2ab7fc27..259244ce 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -100,30 +100,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) check_memleaks (); - printf ("%s: running object ID tests\n", "dbus-test"); - if (!_dbus_object_id_test ()) - die ("object ID"); - - check_memleaks (); - - printf ("%s: running object registry tests\n", "dbus-test"); - if (!_dbus_object_registry_test ()) - die ("object registry"); - - check_memleaks (); - printf ("%s: running object tree tests\n", "dbus-test"); if (!_dbus_object_tree_test ()) die ("object tree"); check_memleaks (); - printf ("%s: running object tests\n", "dbus-test"); - if (!_dbus_object_test ()) - die ("object"); - - check_memleaks (); - printf ("%s: running marshalling tests\n", "dbus-test"); if (!_dbus_marshal_test ()) die ("marshalling"); diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index b6c02669..cbbc8638 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -53,9 +53,6 @@ dbus_bool_t _dbus_sysdeps_test (void); dbus_bool_t _dbus_spawn_test (const char *test_data_dir); dbus_bool_t _dbus_userdb_test (const char *test_data_dir); dbus_bool_t _dbus_memory_test (void); -dbus_bool_t _dbus_object_test (void); -dbus_bool_t _dbus_object_id_test (void); -dbus_bool_t _dbus_object_registry_test (void); dbus_bool_t _dbus_object_tree_test (void); dbus_bool_t _dbus_pending_call_test (const char *test_data_dir); diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index 81c3fbfe..b604a397 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -227,7 +227,6 @@ init_global_locks (void) LOCK_ADDR (message_slots), LOCK_ADDR (atomic), LOCK_ADDR (message_handler), - LOCK_ADDR (callback_object), LOCK_ADDR (bus), LOCK_ADDR (shutdown_funcs), LOCK_ADDR (system_users) diff --git a/dbus/dbus.h b/dbus/dbus.h index 12a087f5..051cb5fa 100644 --- a/dbus/dbus.h +++ b/dbus/dbus.h @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus.h Convenience header including all other headers * - * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 * @@ -38,8 +38,6 @@ #include #include #include -#include -#include #include #include #include -- cgit From 85282c340b8fcd67c10bcf348b1c5d581f7dbd53 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 30 Aug 2003 00:26:00 +0000 Subject: 2003-08-29 Havoc Pennington * dbus/dbus-internals.h: fix _DBUS_N_GLOBAL_LOCKS --- dbus/dbus-internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dbus') diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 1c0f7314..a0c5b194 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -237,7 +237,7 @@ _DBUS_DECLARE_GLOBAL_LOCK (message_handler); _DBUS_DECLARE_GLOBAL_LOCK (bus); _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); _DBUS_DECLARE_GLOBAL_LOCK (system_users); -#define _DBUS_N_GLOBAL_LOCKS (10) +#define _DBUS_N_GLOBAL_LOCKS (9) dbus_bool_t _dbus_threads_init_debug (void); -- cgit From ce969c6347b69180088c592e9184f05d0d3525c4 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 30 Aug 2003 02:56:12 +0000 Subject: 2003-08-29 Havoc Pennington * dbus/dbus-object-tree.c: modify to allow overlapping paths to be registered (struct DBusObjectSubtree): shrink this a lot, since we may have a lot of them (_dbus_object_tree_free_all_unlocked): implement (_dbus_object_tree_dispatch_and_unlock): implement --- dbus/dbus-object-tree.c | 547 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 428 insertions(+), 119 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 31724b7b..a2fc49e2 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -41,11 +41,11 @@ typedef struct DBusObjectSubtree DBusObjectSubtree; -DBusObjectSubtree* _dbus_object_subtree_new (const char **path, - const DBusObjectPathVTable *vtable, - void *user_data); -void _dbus_object_subtree_ref (DBusObjectSubtree *subtree); -void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); +static DBusObjectSubtree* _dbus_object_subtree_new (const char **path, + const DBusObjectPathVTable *vtable, + void *user_data); +static void _dbus_object_subtree_ref (DBusObjectSubtree *subtree); +static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); struct DBusObjectTree { @@ -63,11 +63,11 @@ struct DBusObjectTree struct DBusObjectSubtree { - int refcount; - char **path; - int n_path_elements; - DBusObjectPathVTable vtable; - void *user_data; + DBusAtomic refcount; + DBusObjectPathUnregisterFunction unregister_function; + DBusObjectPathMessageFunction message_function; + void *user_data; + char *path[1]; /**< Allocated as large as necessary */ }; DBusObjectTree* @@ -115,17 +115,9 @@ _dbus_object_tree_unref (DBusObjectTree *tree) if (tree->refcount == 0) { - if (tree->subtrees) - { - int i; - i = 0; - while (i < tree->n_subtrees) - { - _dbus_object_subtree_unref (tree->subtrees[i]); - ++i; - } - } + _dbus_object_tree_free_all_unlocked (tree); + dbus_free (tree->subtrees); dbus_free (tree); } } @@ -134,11 +126,10 @@ static int path_cmp (const char **path_a, const char **path_b) { - /* The comparison is as if the path were flattened - * into a single string. strcmp() considers - * a shorter string less than a longer string - * if the shorter string is the initial part - * of the longer + /* 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; @@ -187,28 +178,29 @@ subtree_qsort_cmp (const void *a, return subtree_cmp (*subtree_a_p, *subtree_b_p); } -/* Returns TRUE if a is a subdir of b or vice - * versa. This is the case if one is a subpath - * of the other. +/* Returns TRUE if container is a parent of child */ static dbus_bool_t -path_overlaps (const char **path_a, - const char **path_b) +path_contains (const char **container, + const char **child) { int i; i = 0; - while (path_a[i] != NULL) + while (child[i] != NULL) { int v; - if (path_b[i] == NULL) - return TRUE; /* b is subpath of a */ - - _dbus_assert (path_a[i] != NULL); - _dbus_assert (path_b[i] != NULL); + 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 (path_a[i], path_b[i]); + v = strcmp (container[i], child[i]); if (v != 0) return FALSE; /* they overlap until here and then are different, @@ -218,9 +210,26 @@ path_overlaps (const char **path_a, ++i; } - /* b is either the same as or a superset of a */ - _dbus_assert (path_a[i] == NULL); - return TRUE; + /* 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 +ensure_sorted (DBusObjectTree *tree) +{ + if (tree->subtrees && !tree->subtrees_sorted) + { + qsort (tree->subtrees, + tree->n_subtrees, + sizeof (DBusObjectSubtree*), + subtree_qsort_cmp); + tree->subtrees_sorted = TRUE; + } } static dbus_bool_t @@ -232,15 +241,8 @@ find_subtree (DBusObjectTree *tree, if (tree->subtrees == NULL) return FALSE; - - if (!tree->subtrees_sorted) - { - qsort (tree->subtrees, - tree->n_subtrees, - sizeof (DBusObjectSubtree*), - subtree_qsort_cmp); - tree->subtrees_sorted = TRUE; - } + + ensure_sorted (tree); /* FIXME this should be a binary search, * as that's the whole point of the sorting @@ -267,20 +269,60 @@ find_subtree (DBusObjectTree *tree, 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); + + /* 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) + { + /* 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 */ + + ++i; + } + + if (idx_p) + *idx_p = found_so_far; + + return FALSE; +} + #ifndef DBUS_DISABLE_CHECKS static void -check_overlap (DBusObjectTree *tree, - const char **path) +check_already_exists (DBusObjectTree *tree, + const char **path) { int i; i = 0; while (i < tree->n_subtrees) { - if (path_overlaps (path, (const char**) tree->subtrees[i]->path)) + if (path_cmp (path, (const char**) tree->subtrees[i]->path) == 0) { - _dbus_warn ("New path (path[0] = %s) overlaps old path (path[0] = %s)\n", - path[0], tree->subtrees[i]->path[0]); + _dbus_warn ("New path (path[0] = %s) already registered\n", + path[0]); } ++i; } @@ -306,9 +348,11 @@ _dbus_object_tree_register (DBusObjectTree *tree, DBusObjectSubtree **new_subtrees; int new_n_subtrees; + _dbus_assert (tree != NULL); + _dbus_assert (vtable->message_function != NULL); _dbus_assert (path != NULL); #ifndef DBUS_DISABLE_CHECKS - check_overlap (tree, path); + check_already_exists (tree, path); #endif _dbus_assert (path[0] != NULL); @@ -319,10 +363,10 @@ _dbus_object_tree_register (DBusObjectTree *tree, /* 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); + new_n_subtrees * sizeof (DBusObjectSubtree*)); if (new_subtrees == NULL) { - _DBUS_ZERO (subtree->vtable); /* to avoid assertion in unref() */ + subtree->unregister_function = NULL; /* to avoid assertion in unref() */ _dbus_object_subtree_unref (subtree); return FALSE; } @@ -351,13 +395,15 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, _dbus_assert (path != NULL); _dbus_assert (path[0] != NULL); - + +#ifndef DBUS_DISABLE_CHECKS if (!find_subtree (tree, path, &i)) { _dbus_warn ("Attempted to unregister subtree (path[0] = %s) which isn't registered\n", path[0]); return; } +#endif subtree = tree->subtrees[i]; @@ -366,19 +412,21 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, &tree->subtrees[i+1], (tree->n_subtrees - i - 1) * sizeof (tree->subtrees[0])); tree->n_subtrees -= 1; - - _dbus_object_subtree_ref (subtree); + subtree->message_function = NULL; + /* Unlock and call application code */ _dbus_connection_unlock (tree->connection); - if (subtree->vtable.unregister_function) + if (subtree->unregister_function) { - (* subtree->vtable.unregister_function) (tree->connection, - (const char**) subtree->path, - subtree->user_data); - _DBUS_ZERO (subtree->vtable); + (* subtree->unregister_function) (tree->connection, + (const char**) subtree->path, + subtree->user_data); + subtree->unregister_function = NULL; } + + _dbus_object_subtree_unref (subtree); } /** @@ -392,15 +440,38 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *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; + 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); + } } /** - * Tries to dispatch a message by directing it to the object tree - * node listed in the message header, if any. + * Tries to dispatch a message by directing it to handler for the + * object path listed in the message header, if any. Messages are + * dispatched first to the registered handler that matches the largest + * number of path elements; that is, message to /foo/bar/baz would go + * to the handler for /foo/bar before the one for /foo. * - * @todo implement + * @todo thread problems * * @param tree the global object tree * @param message the message to dispatch @@ -410,70 +481,184 @@ DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, DBusMessage *message) { + const char **path; + int i; + DBusList *list; + DBusList *link; + DBusHandlerResult result; + + path = NULL; /* dbus_message_get_object_path (message); */ + + if (path == NULL) + 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; + + /* Build a list of all paths that cover the path in the message */ + + list = NULL; + + do + { + DBusObjectSubtree *subtree; + + subtree = tree->subtrees[i]; + + _dbus_object_subtree_ref (subtree); + _dbus_list_append (&list, subtree); + + --i; + + } while (i > 0 && path_contains ((const char**) tree->subtrees[i]->path, + path)); + + /* 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 */ + if (subtree->message_function) + { + _dbus_connection_unlock (tree->connection); + + /* FIXME you could unregister the subtree in another thread + * 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) + goto free_and_return; + + _dbus_connection_lock (tree->connection); + } + + link = next; + } + + _dbus_connection_unlock (tree->connection); + + free_and_return: + while (list != NULL) + { + link = _dbus_list_get_first_link (&list); + _dbus_object_subtree_unref (link->data); + _dbus_list_remove_link (&list, link); + } + + 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. + * + * @param array array to duplicate. + * @returns newly-allocated subtree + */ +static DBusObjectSubtree* +allocate_subtree_object (const char **array) +{ + 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; + + 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; + + 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; + + path_dest[i] = p; + + this_len = strlen (array[i]); + memcpy (p, array[i], this_len + 1); + p += this_len + 1; + + ++i; + } + + return subtree; } -DBusObjectSubtree* +static DBusObjectSubtree* _dbus_object_subtree_new (const char **path, const DBusObjectPathVTable *vtable, void *user_data) { DBusObjectSubtree *subtree; - subtree = dbus_new0 (DBusObjectSubtree, 1); + subtree = allocate_subtree_object (path); if (subtree == NULL) goto oom; _dbus_assert (path != NULL); _dbus_assert (path[0] != NULL); - - subtree->path = _dbus_dup_string_array (path); - if (subtree->path == NULL) - goto oom; - subtree->vtable = *vtable; + subtree->message_function = vtable->message_function; + subtree->unregister_function = vtable->unregister_function; subtree->user_data = user_data; - - subtree->refcount = 1; - - /* count path elements */ - while (subtree->path[subtree->n_path_elements]) - subtree->n_path_elements += 1; + subtree->refcount.value = 1; return subtree; oom: if (subtree) { - dbus_free_string_array (subtree->path); dbus_free (subtree); } return NULL; } -void +static void _dbus_object_subtree_ref (DBusObjectSubtree *subtree) { - _dbus_assert (subtree->refcount > 0); - - subtree->refcount += 1; + _dbus_assert (subtree->refcount.value > 0); + _dbus_atomic_inc (&subtree->refcount); } -void +static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree) { - _dbus_assert (subtree->refcount > 0); - - subtree->refcount -= 1; + _dbus_assert (subtree->refcount.value > 0); - if (subtree->refcount == 0) + if (_dbus_atomic_dec (&subtree->refcount) == 1) { - _dbus_assert (subtree->vtable.unregister_function == NULL); - - dbus_free_string_array (subtree->path); - + _dbus_assert (subtree->unregister_function == NULL); + _dbus_assert (subtree->message_function == NULL); dbus_free (subtree); } } @@ -484,6 +669,40 @@ _dbus_object_subtree_unref (DBusObjectSubtree *subtree) #include "dbus-test.h" #include +static char* +flatten_path (const char **path) +{ + DBusString str; + int i; + char *s; + + if (!_dbus_string_init (&str)) + return NULL; + + i = 0; + while (path[i]) + { + if (!_dbus_string_append_byte (&str, '/')) + goto nomem; + + if (!_dbus_string_append (&str, path[i])) + goto nomem; + + ++i; + } + + if (!_dbus_string_steal_data (&str, &s)) + goto nomem; + + _dbus_string_free (&str); + + return s; + + nomem: + _dbus_string_free (&str); + return NULL; +} + static dbus_bool_t test_subtree_cmp (const char **path1, const char **path2, @@ -531,12 +750,72 @@ test_subtree_cmp (const char **path1, } static void -test_path_overlap (const char **path1, - const char **path2, - dbus_bool_t expected) +test_path_contains (const char **path1, + const char **path2, + dbus_bool_t expected) +{ + 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) + { + 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); + } + } + /* 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_free (s1); + dbus_free (s2); + + exit (1); + } +} + +static void +test_path_copy (const char **path) { - _dbus_assert (path_overlaps (path1, path2) == expected); - _dbus_assert (path_overlaps (path2, path1) == expected); + DBusObjectSubtree *subtree; + + subtree = allocate_subtree_object (path); + if (subtree == NULL) + return; + + _dbus_assert (path_cmp (path, (const char**) subtree->path) == 0); + + dbus_free (subtree); } static dbus_bool_t @@ -547,33 +826,63 @@ object_tree_test_iteration (void *data) const char *path3[] = { "foo", "bar", "baz", NULL }; const char *path4[] = { "foo", "bar", "boo", NULL }; const char *path5[] = { "blah", NULL }; + const char *path6[] = { "blah", "boof", NULL }; DBusObjectSubtree *subtree1; DBusObjectSubtree *subtree2; DBusObjectTree *tree; + 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; subtree1 = NULL; subtree2 = NULL; - test_path_overlap (path1, path1, TRUE); - test_path_overlap (path1, path2, TRUE); - test_path_overlap (path1, path3, TRUE); - test_path_overlap (path1, path4, TRUE); - test_path_overlap (path1, path5, FALSE); - - test_path_overlap (path2, path2, TRUE); - test_path_overlap (path2, path3, TRUE); - test_path_overlap (path2, path4, TRUE); - test_path_overlap (path2, path5, FALSE); - - test_path_overlap (path3, path3, TRUE); - test_path_overlap (path3, path4, FALSE); - test_path_overlap (path3, path5, FALSE); - - test_path_overlap (path4, path4, TRUE); - test_path_overlap (path4, path5, FALSE); - - test_path_overlap (path5, path5, TRUE); + 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; -- cgit From 9a0e83f509bd927b555ff75319f8df66ca61087e Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 30 Aug 2003 17:09:24 +0000 Subject: 2003-08-30 Havoc Pennington * dbus/dbus-object-tree.c: write tests and fix the discovered bugs --- dbus/dbus-object-tree.c | 303 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 279 insertions(+), 24 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index a2fc49e2..379e2f04 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -254,18 +254,22 @@ find_subtree (DBusObjectTree *tree, v = path_cmp (path, (const char**) tree->subtrees[i]->path); + if (v == 0) { if (idx_p) *idx_p = i; + return TRUE; } - else if (v > 0) - return FALSE; + else if (v < 0) + { + return FALSE; + } ++i; } - + return FALSE; } @@ -366,12 +370,13 @@ _dbus_object_tree_register (DBusObjectTree *tree, new_n_subtrees * sizeof (DBusObjectSubtree*)); if (new_subtrees == NULL) { - subtree->unregister_function = NULL; /* to avoid assertion in unref() */ + subtree->unregister_function = NULL; + subtree->message_function = NULL; _dbus_object_subtree_unref (subtree); return FALSE; } - tree->subtrees[tree->n_subtrees] = subtree; + new_subtrees[tree->n_subtrees] = subtree; tree->subtrees_sorted = FALSE; tree->n_subtrees = new_n_subtrees; tree->subtrees = new_subtrees; @@ -396,15 +401,15 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, _dbus_assert (path != NULL); _dbus_assert (path[0] != NULL); -#ifndef DBUS_DISABLE_CHECKS if (!find_subtree (tree, path, &i)) { - _dbus_warn ("Attempted to unregister subtree (path[0] = %s) which isn't registered\n", - path[0]); + _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", + path[0], path[1] ? path[1] : "null"); return; } -#endif + _dbus_assert (i >= 0); + subtree = tree->subtrees[i]; /* assumes a 0-byte memmove is OK */ @@ -416,7 +421,10 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, subtree->message_function = NULL; /* Unlock and call application code */ - _dbus_connection_unlock (tree->connection); +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); if (subtree->unregister_function) { @@ -449,6 +457,8 @@ _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) 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 */ @@ -527,7 +537,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, /* message_function is NULL if we're unregistered */ if (subtree->message_function) { - _dbus_connection_unlock (tree->connection); +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); /* FIXME you could unregister the subtree in another thread * before we invoke the callback, and I can't figure out a @@ -539,14 +552,20 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, if (result == DBUS_HANDLER_RESULT_HANDLED) goto free_and_return; - - _dbus_connection_lock (tree->connection); + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_lock (tree->connection); } link = next; } - - _dbus_connection_unlock (tree->connection); + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); free_and_return: while (list != NULL) @@ -703,6 +722,29 @@ flatten_path (const char **path) return NULL; } +static void +spew_tree (DBusObjectTree *tree) +{ + int i; + + printf ("Tree of %d subpaths\n", + tree->n_subtrees); + + i = 0; + while (i < tree->n_subtrees) + { + 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, @@ -818,6 +860,56 @@ test_path_copy (const char **path) dbus_free (subtree); } +typedef struct +{ + dbus_bool_t message_handled; + dbus_bool_t handler_unregistered; + +} TreeTestData; + + +static void +test_unregister_function (DBusConnection *connection, + const char **path, + void *user_data) +{ + TreeTestData *ttd = user_data; + + ttd->handler_unregistered = TRUE; +} + +static DBusHandlerResult +test_message_function (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + TreeTestData *ttd = user_data; + + ttd->message_handled = TRUE; + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static dbus_bool_t +do_register (DBusObjectTree *tree, + const char **path, + int i, + TreeTestData *tree_test_data) +{ + DBusObjectPathVTable vtable = { test_unregister_function, + test_message_function, NULL }; + + tree_test_data[i].message_handled = FALSE; + tree_test_data[i].handler_unregistered = FALSE; + + if (!_dbus_object_tree_register (tree, path, + &vtable, + &tree_test_data[i])) + return FALSE; + + return TRUE; +} + static dbus_bool_t object_tree_test_iteration (void *data) { @@ -827,10 +919,10 @@ object_tree_test_iteration (void *data) const char *path4[] = { "foo", "bar", "boo", NULL }; const char *path5[] = { "blah", NULL }; const char *path6[] = { "blah", "boof", NULL }; - DBusObjectSubtree *subtree1; - DBusObjectSubtree *subtree2; DBusObjectTree *tree; - + TreeTestData tree_test_data[6]; + int i; + test_path_copy (path1); test_path_copy (path2); test_path_copy (path3); @@ -839,8 +931,6 @@ object_tree_test_iteration (void *data) test_path_copy (path6); tree = NULL; - subtree1 = NULL; - subtree2 = NULL; test_path_contains (path1, path1, TRUE); test_path_contains (path1, path2, TRUE); @@ -905,12 +995,177 @@ 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; + + _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)); + + if (!do_register (tree, path2, 1, 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)); + + if (!do_register (tree, path3, 2, 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)); + + 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, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + + if (!do_register (tree, path5, 4, 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)); + + if (!do_register (tree, path6, 5, 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)); + + /* Check that destroying tree calls unregister funcs */ + _dbus_object_tree_unref (tree); + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) + { + _dbus_assert (tree_test_data[i].handler_unregistered); + _dbus_assert (!tree_test_data[i].message_handled); + ++i; + } + /* Now start again and try the individual unregister function */ + 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)) + goto out; + if (!do_register (tree, path3, 2, tree_test_data)) + goto out; + if (!do_register (tree, path4, 3, tree_test_data)) + goto out; + if (!do_register (tree, path5, 4, tree_test_data)) + goto out; + if (!do_register (tree, path6, 5, tree_test_data)) + goto out; + + _dbus_object_tree_unregister_and_unlock (tree, path1); + + _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_object_tree_unregister_and_unlock (tree, path2); + + _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_object_tree_unregister_and_unlock (tree, path3); + + _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_object_tree_unregister_and_unlock (tree, path4); + + _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_object_tree_unregister_and_unlock (tree, path5); + + _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_object_tree_unregister_and_unlock (tree, path6); + + _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)); + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) + { + _dbus_assert (tree_test_data[i].handler_unregistered); + _dbus_assert (!tree_test_data[i].message_handled); + ++i; + } + + /* 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)) + goto out; + if (!do_register (tree, path3, 2, tree_test_data)) + goto out; + if (!do_register (tree, path4, 3, tree_test_data)) + goto out; + if (!do_register (tree, path5, 4, tree_test_data)) + goto out; + if (!do_register (tree, path6, 5, tree_test_data)) + goto out; + + /* FIXME (once messages have an object path field) */ + out: - if (subtree1) - _dbus_object_subtree_unref (subtree1); - if (subtree2) - _dbus_object_subtree_unref (subtree2); if (tree) _dbus_object_tree_unref (tree); -- cgit From 5fd1e389e1c1c12ad4a55c2af6abdc8e7a2f6d41 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 31 Aug 2003 01:51:44 +0000 Subject: 2003-08-30 Havoc Pennington * 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 --- dbus/dbus-bus.c | 29 +- dbus/dbus-connection.c | 5 +- dbus/dbus-connection.h | 1 - dbus/dbus-marshal.c | 127 ++++- dbus/dbus-message-builder.c | 103 ++++ dbus/dbus-message.c | 291 +++++++++-- dbus/dbus-message.h | 16 +- dbus/dbus-object-tree.c | 1144 +++++++++++++++++++++++-------------------- dbus/dbus-protocol.h | 17 +- dbus/dbus-string.c | 119 ++++- dbus/dbus-string.h | 3 + dbus/dbus-test.c | 2 +- 12 files changed, 1247 insertions(+), 610 deletions(-) (limited to 'dbus') 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 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 marshals a UINT64 * DOUBLE 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 @@ -467,6 +519,25 @@ _dbus_message_data_load (DBusString *dest, goto parse_failed; } } + 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")) { @@ -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; @@ -1352,6 +1404,78 @@ dbus_message_get_type (DBusMessage *message) return type; } +/** + * 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 @@ -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])) @@ -910,6 +892,68 @@ do_register (DBusObjectTree *tree, return TRUE; } +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) { @@ -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 @@ -2845,6 +2845,74 @@ _dbus_string_validate_nul (const DBusString *str, return TRUE; } +/** + * 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., @@ -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"); -- cgit From 1dd3f1788f1b4c9af2f4fa744abdb7892d0a14b9 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 31 Aug 2003 03:25:24 +0000 Subject: 2003-08-30 Havoc Pennington * dbus/dbus-connection.c: purge DBusMessageHandler * dbus/dbus-message-handler.c: remove DBusMessageHandler, just use callbacks everywhere --- dbus/Makefile.am | 2 - dbus/dbus-connection-internal.h | 9 - dbus/dbus-connection.c | 203 +++++++++++++--------- dbus/dbus-connection.h | 21 ++- dbus/dbus-internals.h | 3 +- dbus/dbus-message-handler.c | 363 ---------------------------------------- dbus/dbus-message-handler.h | 59 ------- dbus/dbus-test.c | 6 - dbus/dbus-test.h | 1 - dbus/dbus-threads.c | 1 - dbus/dbus.h | 1 - 11 files changed, 138 insertions(+), 531 deletions(-) delete mode 100644 dbus/dbus-message-handler.c delete mode 100644 dbus/dbus-message-handler.h (limited to 'dbus') diff --git a/dbus/Makefile.am b/dbus/Makefile.am index f8509cce..f377b2a8 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -16,7 +16,6 @@ dbusinclude_HEADERS= \ dbus-macros.h \ dbus-memory.h \ dbus-message.h \ - dbus-message-handler.h \ dbus-pending-call.h \ dbus-protocol.h \ dbus-server.h \ @@ -41,7 +40,6 @@ DBUS_LIB_SOURCES= \ dbus-keyring.c \ dbus-keyring.h \ dbus-message.c \ - dbus-message-handler.c \ dbus-message-internal.h \ dbus-object-tree.c \ dbus-object-tree.h \ diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 93b1b4a3..5a04dece 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -77,15 +77,6 @@ void _dbus_connection_do_iteration (DBusConnection unsigned int flags, int timeout_milliseconds); void _dbus_connection_notify_disconnected (DBusConnection *connection); -void _dbus_connection_handler_destroyed_locked (DBusConnection *connection, - DBusMessageHandler *handler); -dbus_bool_t _dbus_message_handler_add_connection (DBusMessageHandler *handler, - DBusConnection *connection); -void _dbus_message_handler_remove_connection (DBusMessageHandler *handler, - DBusConnection *connection); -DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message); DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, int timeout_milliseconds, diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 86678673..608634d2 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -31,7 +31,6 @@ #include "dbus-list.h" #include "dbus-hash.h" #include "dbus-message-internal.h" -#include "dbus-message-handler.h" #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-dataslot.h" @@ -125,6 +124,16 @@ * @{ */ +typedef struct DBusMessageFilter DBusMessageFilter; + +struct DBusMessageFilter +{ + DBusAtomic refcount; + DBusHandleMessageFunction function; + void *user_data; + DBusFreeFunction free_user_data_function; +}; + static dbus_bool_t _dbus_modify_sigpipe = TRUE; /** @@ -189,6 +198,26 @@ static void _dbus_connection_update_dispatch_status_and_unlock (DB DBusDispatchStatus new_status); static void _dbus_connection_last_unref (DBusConnection *connection); +static void +_dbus_message_filter_ref (DBusMessageFilter *filter) +{ + _dbus_assert (filter->refcount.value > 0); + _dbus_atomic_inc (&filter->refcount); +} + +static void +_dbus_message_filter_unref (DBusMessageFilter *filter) +{ + _dbus_assert (filter->refcount.value > 0); + + if (_dbus_atomic_dec (&filter->refcount) == 1) + { + if (filter->free_user_data_function) + (* filter->free_user_data_function) (filter->user_data); + + dbus_free (filter); + } +} /** * Acquires the connection lock. @@ -977,40 +1006,6 @@ _dbus_connection_get_next_client_serial (DBusConnection *connection) return serial; } -/** - * Used to notify a connection when a DBusMessageHandler is - * destroyed, so the connection can drop any reference - * to the handler. This is a private function, but still - * takes the connection lock. Don't call it with the lock held. - * - * @todo needs to check in pending_replies too. - * - * @param connection the connection - * @param handler the handler - */ -void -_dbus_connection_handler_destroyed_locked (DBusConnection *connection, - DBusMessageHandler *handler) -{ - DBusList *link; - - CONNECTION_LOCK (connection); - - link = _dbus_list_get_first_link (&connection->filter_list); - while (link != NULL) - { - DBusMessageHandler *h = link->data; - DBusList *next = _dbus_list_get_next_link (&connection->filter_list, link); - - if (h == handler) - _dbus_list_remove_link (&connection->filter_list, - link); - - link = next; - } - CONNECTION_UNLOCK (connection); -} - /** * A callback for use with dbus_watch_new() to create a DBusWatch. * @@ -1173,18 +1168,22 @@ _dbus_connection_last_unref (DBusConnection *connection) connection->timeouts = NULL; _dbus_data_slot_list_free (&connection->slot_list); - /* ---- Done with stuff that invokes application callbacks */ link = _dbus_list_get_first_link (&connection->filter_list); while (link != NULL) { - DBusMessageHandler *h = link->data; + DBusMessageFilter *filter = link->data; DBusList *next = _dbus_list_get_next_link (&connection->filter_list, link); - - _dbus_message_handler_remove_connection (h, connection); + + filter->function = NULL; + _dbus_message_filter_unref (filter); /* calls app callback */ + link->data = NULL; link = next; } + _dbus_list_clear (&connection->filter_list); + + /* ---- Done with stuff that invokes application callbacks */ _dbus_object_tree_unref (connection->objects); @@ -2456,7 +2455,7 @@ dbus_connection_dispatch (DBusConnection *connection) } _dbus_list_foreach (&filter_list_copy, - (DBusForeachFunction)dbus_message_handler_ref, + (DBusForeachFunction)_dbus_message_filter_ref, NULL); /* We're still protected from dispatch() reentrancy here @@ -2467,12 +2466,11 @@ dbus_connection_dispatch (DBusConnection *connection) link = _dbus_list_get_first_link (&filter_list_copy); while (link != NULL) { - DBusMessageHandler *handler = link->data; + DBusMessageFilter *filter = link->data; DBusList *next = _dbus_list_get_next_link (&filter_list_copy, link); _dbus_verbose (" running filter on message %p\n", message); - result = _dbus_message_handler_handle_message (handler, connection, - message); + result = (* filter->function) (connection, message, filter->user_data); if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) break; @@ -2481,7 +2479,7 @@ dbus_connection_dispatch (DBusConnection *connection) } _dbus_list_foreach (&filter_list_copy, - (DBusForeachFunction)dbus_message_handler_unref, + (DBusForeachFunction)_dbus_message_filter_unref, NULL); _dbus_list_clear (&filter_list_copy); @@ -2928,83 +2926,126 @@ dbus_connection_set_unix_user_function (DBusConnection *connection, } /** - * Adds a message filter. Filters are handlers that are run on - * all incoming messages, prior to the objects - * registered with dbus_connection_register_object(). - * Filters are run in the order that they were added. - * The same handler can be added as a filter more than once, in - * which case it will be run more than once. - * Filters added during a filter callback won't be run on the - * message being processed. - * - * The connection does NOT add a reference to the message handler; - * instead, if the message handler is finalized, the connection simply - * forgets about it. Thus the caller of this function must keep a - * reference to the message handler. + * Adds a message filter. Filters are handlers that are run on all + * incoming messages, prior to the objects registered with + * dbus_connection_register_object_path(). Filters are run in the + * order that they were added. The same handler can be added as a + * filter more than once, in which case it will be run more than once. + * Filters added during a filter callback won't be run on the message + * being processed. * * @todo we don't run filters on messages while blocking without * entering the main loop, since filters are run as part of * dbus_connection_dispatch(). * * @param connection the connection - * @param handler the handler + * @param function function to handle messages + * @param user_data user data to pass to the function + * @param free_data_function function to use for freeing user data * @returns #TRUE on success, #FALSE if not enough memory. */ dbus_bool_t -dbus_connection_add_filter (DBusConnection *connection, - DBusMessageHandler *handler) +dbus_connection_add_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data, + DBusFreeFunction free_data_function) { + DBusMessageFilter *filter; + _dbus_return_val_if_fail (connection != NULL, FALSE); - _dbus_return_val_if_fail (handler != NULL, FALSE); + _dbus_return_val_if_fail (function != NULL, FALSE); + + filter = dbus_new0 (DBusMessageFilter, 1); + if (filter == NULL) + return FALSE; + filter->refcount.value = 1; + CONNECTION_LOCK (connection); - if (!_dbus_message_handler_add_connection (handler, connection)) - { - CONNECTION_UNLOCK (connection); - return FALSE; - } if (!_dbus_list_append (&connection->filter_list, - handler)) + filter)) { - _dbus_message_handler_remove_connection (handler, connection); + _dbus_message_filter_unref (filter); CONNECTION_UNLOCK (connection); return FALSE; } + /* Fill in filter after all memory allocated, + * so we don't run the free_user_data_function + * if the add_filter() fails + */ + + filter->function = function; + filter->user_data = user_data; + filter->free_user_data_function = free_data_function; + CONNECTION_UNLOCK (connection); return TRUE; } /** * Removes a previously-added message filter. It is a programming - * error to call this function for a handler that has not - * been added as a filter. If the given handler was added - * more than once, only one instance of it will be removed - * (the most recently-added instance). + * error to call this function for a handler that has not been added + * as a filter. If the given handler was added more than once, only + * one instance of it will be removed (the most recently-added + * instance). * * @param connection the connection * @param handler the handler to remove * */ void -dbus_connection_remove_filter (DBusConnection *connection, - DBusMessageHandler *handler) +dbus_connection_remove_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data) { + DBusList *link; + DBusMessageFilter *filter; + _dbus_return_if_fail (connection != NULL); - _dbus_return_if_fail (handler != NULL); + _dbus_return_if_fail (function != NULL); CONNECTION_LOCK (connection); - if (!_dbus_list_remove_last (&connection->filter_list, handler)) + + filter = NULL; + + link = _dbus_list_get_last_link (&connection->filter_list); + while (link != NULL) { - _dbus_warn ("Tried to remove a DBusConnection filter that had not been added\n"); - CONNECTION_UNLOCK (connection); - return; + filter = link->data; + + if (filter->function == function && + filter->user_data == user_data) + { + _dbus_list_remove_link (&connection->filter_list, link); + filter->function = NULL; + + break; + } + + link = _dbus_list_get_prev_link (&connection->filter_list, link); } + + CONNECTION_UNLOCK (connection); - _dbus_message_handler_remove_connection (handler, connection); +#ifndef DBUS_DISABLE_CHECKS + if (filter == NULL) + { + _dbus_warn ("Attempt to remove filter function %p user data %p, but no such filter has been added\n", + function, user_data); + return; + } +#endif + + /* Call application code */ + if (filter->free_user_data_function) + (* filter->free_user_data_function) (filter->user_data); - CONNECTION_UNLOCK (connection); + filter->free_user_data_function = NULL; + filter->user_data = NULL; + + _dbus_message_filter_unref (filter); } /** diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 0b346530..c5dee7f0 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -35,7 +35,6 @@ DBUS_BEGIN_DECLS; typedef struct DBusWatch DBusWatch; typedef struct DBusTimeout DBusTimeout; -typedef struct DBusMessageHandler DBusMessageHandler; typedef struct DBusPreallocatedSend DBusPreallocatedSend; typedef struct DBusPendingCall DBusPendingCall; typedef struct DBusConnection DBusConnection; @@ -89,6 +88,11 @@ typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection, typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, void *user_data); + +typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusConnection *connection, + DBusMessage *message, + void *user_data); + DBusConnection* dbus_connection_open (const char *address, DBusError *error); void dbus_connection_ref (DBusConnection *connection); @@ -162,11 +166,16 @@ void dbus_timeout_set_data (DBusTimeout *timeout, dbus_bool_t dbus_timeout_handle (DBusTimeout *timeout); dbus_bool_t dbus_timeout_get_enabled (DBusTimeout *timeout); -/* Handlers */ -dbus_bool_t dbus_connection_add_filter (DBusConnection *connection, - DBusMessageHandler *handler); -void dbus_connection_remove_filter (DBusConnection *connection, - DBusMessageHandler *handler); +/* Filters */ + +dbus_bool_t dbus_connection_add_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data, + DBusFreeFunction free_data_function); +void dbus_connection_remove_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data); + /* Other */ dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p); diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index a0c5b194..06a011e3 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -233,11 +233,10 @@ _DBUS_DECLARE_GLOBAL_LOCK (connection_slots); _DBUS_DECLARE_GLOBAL_LOCK (server_slots); _DBUS_DECLARE_GLOBAL_LOCK (message_slots); _DBUS_DECLARE_GLOBAL_LOCK (atomic); -_DBUS_DECLARE_GLOBAL_LOCK (message_handler); _DBUS_DECLARE_GLOBAL_LOCK (bus); _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); _DBUS_DECLARE_GLOBAL_LOCK (system_users); -#define _DBUS_N_GLOBAL_LOCKS (9) +#define _DBUS_N_GLOBAL_LOCKS (8) dbus_bool_t _dbus_threads_init_debug (void); diff --git a/dbus/dbus-message-handler.c b/dbus/dbus-message-handler.c deleted file mode 100644 index 2e8a8b64..00000000 --- a/dbus/dbus-message-handler.c +++ /dev/null @@ -1,363 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-message-handler.c Sender/receiver of messages. - * - * Copyright (C) 2002, 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "dbus-internals.h" -#include "dbus-message-handler.h" -#include "dbus-list.h" -#include "dbus-threads.h" -#include "dbus-test.h" -#include "dbus-connection-internal.h" - -/** - * @defgroup DBusMessageHandlerInternals DBusMessageHandler implementation details - * @ingroup DBusInternals - * @brief DBusMessageHandler private implementation details. - * - * The guts of DBusMessageHandler and its methods. - * - * @{ - */ - -_DBUS_DEFINE_GLOBAL_LOCK (message_handler); - -/** - * @brief Internals of DBusMessageHandler - * - * Object that can send and receive messages. - */ -struct DBusMessageHandler -{ - DBusAtomic refcount; /**< reference count */ - - DBusHandleMessageFunction function; /**< handler function */ - void *user_data; /**< user data for function */ - DBusFreeFunction free_user_data; /**< free the user data */ - - DBusList *connections; /**< connections we're registered with */ -}; - -/** - * Add this connection to the list used by this message handler. - * When the message handler goes away, the connection - * will be notified. - * - * @param handler the message handler - * @param connection the connection - * @returns #FALSE if not enough memory - */ -dbus_bool_t -_dbus_message_handler_add_connection (DBusMessageHandler *handler, - DBusConnection *connection) -{ - dbus_bool_t res; - - _DBUS_LOCK (message_handler); - /* This is a bit wasteful - we just put the connection in the list - * once per time it's added. :-/ - */ - if (!_dbus_list_prepend (&handler->connections, connection)) - res = FALSE; - else - res = TRUE; - - _DBUS_UNLOCK (message_handler); - - return res; -} - -/** - * Reverses the effect of _dbus_message_handler_add_connection(). - * @param handler the message handler - * @param connection the connection - */ -void -_dbus_message_handler_remove_connection (DBusMessageHandler *handler, - DBusConnection *connection) -{ - _DBUS_LOCK (message_handler); - if (!_dbus_list_remove (&handler->connections, connection)) - _dbus_warn ("Function _dbus_message_handler_remove_connection() called when the connection hadn't been added\n"); - _DBUS_UNLOCK (message_handler); -} - - -/** - * Handles the given message, by dispatching the handler function - * for this DBusMessageHandler, if any. - * - * @param handler the handler - * @param connection the connection that received the message - * @param message the message - * - * @returns what to do with the message - */ -DBusHandlerResult -_dbus_message_handler_handle_message (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message) -{ - DBusHandleMessageFunction function; - void *user_data; - - _DBUS_LOCK (message_handler); - function = handler->function; - user_data = handler->user_data; - _DBUS_UNLOCK (message_handler); - - /* This function doesn't ref handler/connection/message - * since that's done in dbus_connection_dispatch(). - */ - if (function != NULL) - return (* function) (handler, connection, message, user_data); - else - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -/** @} */ - -/** - * @defgroup DBusMessageHandler DBusMessageHandler - * @ingroup DBus - * @brief Message processor - * - * A DBusMessageHandler is an object that can send and receive - * messages. Typically the handler is registered with one or - * more DBusConnection objects and processes some types of - * messages received from the connection. - * - * @{ - */ - -/** - * @typedef DBusMessageHandler - * - * Opaque data type representing a message handler. - */ - -/** - * Creates a new message handler. The handler function - * may be #NULL for a no-op handler or a handler to - * be assigned a function later. - * - * @param function function to call to handle a message - * @param user_data data to pass to the function - * @param free_user_data function to call to free the user data - * @returns a new DBusMessageHandler or #NULL if no memory. - */ -DBusMessageHandler* -dbus_message_handler_new (DBusHandleMessageFunction function, - void *user_data, - DBusFreeFunction free_user_data) -{ - DBusMessageHandler *handler; - - handler = dbus_new (DBusMessageHandler, 1); - - if (handler == NULL) - return NULL; - - handler->refcount.value = 1; - handler->function = function; - handler->user_data = user_data; - handler->free_user_data = free_user_data; - handler->connections = NULL; - - return handler; -} - -/** - * Increments the reference count on a message handler. - * - * @param handler the handler - */ -void -dbus_message_handler_ref (DBusMessageHandler *handler) -{ - _dbus_return_if_fail (handler != NULL); - - _dbus_atomic_inc (&handler->refcount); -} - -/** - * Decrements the reference count on a message handler, - * freeing the handler if the count reaches 0. - * - * @param handler the handler - */ -void -dbus_message_handler_unref (DBusMessageHandler *handler) -{ - dbus_bool_t last_unref; - - _dbus_return_if_fail (handler != NULL); - - last_unref = (_dbus_atomic_dec (&handler->refcount) == 1); - - if (last_unref) - { - DBusList *link; - - if (handler->free_user_data) - (* handler->free_user_data) (handler->user_data); - - link = _dbus_list_get_first_link (&handler->connections); - while (link != NULL) - { - DBusConnection *connection = link->data; - - _dbus_connection_handler_destroyed_locked (connection, handler); - - link = _dbus_list_get_next_link (&handler->connections, link); - } - - _dbus_list_clear (&handler->connections); - - dbus_free (handler); - } -} - -/** - * Gets the user data for the handler (the same user data - * passed to the handler function.) - * - * @param handler the handler - * @returns the user data - */ -void* -dbus_message_handler_get_data (DBusMessageHandler *handler) -{ - void* user_data; - - _dbus_return_val_if_fail (handler != NULL, NULL); - - _DBUS_LOCK (message_handler); - user_data = handler->user_data; - _DBUS_UNLOCK (message_handler); - return user_data; -} - -/** - * Sets the user data for the handler (the same user data - * to be passed to the handler function). Frees any previously-existing - * user data with the previous free_user_data function. - * - * @param handler the handler - * @param user_data the user data - * @param free_user_data free function for the data - */ -void -dbus_message_handler_set_data (DBusMessageHandler *handler, - void *user_data, - DBusFreeFunction free_user_data) -{ - DBusFreeFunction old_free_func; - void *old_user_data; - - _dbus_return_if_fail (handler != NULL); - - _DBUS_LOCK (message_handler); - old_free_func = handler->free_user_data; - old_user_data = handler->user_data; - - handler->user_data = user_data; - handler->free_user_data = free_user_data; - _DBUS_UNLOCK (message_handler); - - if (old_free_func) - (* old_free_func) (old_user_data); - -} - -/** - * Sets the handler function. Call dbus_message_handler_set_data() - * to set the user data for the function. - * - * @param handler the handler - * @param function the function - */ -void -dbus_message_handler_set_function (DBusMessageHandler *handler, - DBusHandleMessageFunction function) -{ - _dbus_return_if_fail (handler != NULL); - - _DBUS_LOCK (message_handler); - handler->function = function; - _DBUS_UNLOCK (message_handler); -} - -/** @} */ - -#ifdef DBUS_BUILD_TESTS -static DBusHandlerResult -test_handler (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static void -free_test_data (void *data) -{ - /* does nothing */ -} - -/** - * @ingroup DBusMessageHandlerInternals - * Unit test for DBusMessageHandler. - * - * @returns #TRUE on success. - */ -dbus_bool_t -_dbus_message_handler_test (const char *test_data_dir) -{ - DBusMessageHandler *handler; - -#define TEST_DATA ((void*) 0xcafebabe) - - handler = dbus_message_handler_new (test_handler, - TEST_DATA, - free_test_data); - - _dbus_assert (handler != NULL); - _dbus_assert (handler->function == test_handler); - - if (dbus_message_handler_get_data (handler) != TEST_DATA) - _dbus_assert_not_reached ("got wrong data"); - - dbus_message_handler_set_data (handler, NULL, NULL); - if (dbus_message_handler_get_data (handler) != NULL) - _dbus_assert_not_reached ("got wrong data after set"); - - dbus_message_handler_set_function (handler, NULL); - _dbus_assert (handler->function == NULL); - - dbus_message_handler_ref (handler); - dbus_message_handler_unref (handler); - dbus_message_handler_unref (handler); - - return TRUE; -} -#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-message-handler.h b/dbus/dbus-message-handler.h deleted file mode 100644 index dac015ac..00000000 --- a/dbus/dbus-message-handler.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-message-handler.h Sender/receiver of messages. - * - * Copyright (C) 2002 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) -#error "Only can be included directly, this file may disappear or change contents." -#endif - -#ifndef DBUS_MESSAGE_HANDLER_H -#define DBUS_MESSAGE_HANDLER_H - -#include -#include -#include - -DBUS_BEGIN_DECLS; - -typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data); - -DBusMessageHandler* dbus_message_handler_new (DBusHandleMessageFunction function, - void *user_data, - DBusFreeFunction free_user_data); - - -void dbus_message_handler_ref (DBusMessageHandler *handler); -void dbus_message_handler_unref (DBusMessageHandler *handler); - - -void* dbus_message_handler_get_data (DBusMessageHandler *handler); -void dbus_message_handler_set_data (DBusMessageHandler *handler, - void *data, - DBusFreeFunction free_user_data); -void dbus_message_handler_set_function (DBusMessageHandler *handler, - DBusHandleMessageFunction function); - -DBUS_END_DECLS; - -#endif /* DBUS_MESSAGE_HANDLER_H */ diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 774a3138..b7a09a0e 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -135,12 +135,6 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) die ("messages"); check_memleaks (); - - printf ("%s: running message handler tests\n", "dbus-test"); - if (!_dbus_message_handler_test (test_data_dir)) - die ("message handler"); - - check_memleaks (); printf ("%s: running hash table tests\n", "dbus-test"); if (!_dbus_hash_test ()) diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index cbbc8638..02b2c279 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -43,7 +43,6 @@ dbus_bool_t _dbus_mem_pool_test (void); dbus_bool_t _dbus_string_test (void); dbus_bool_t _dbus_address_test (void); dbus_bool_t _dbus_message_test (const char *test_data_dir); -dbus_bool_t _dbus_message_handler_test (const char *test_data_dir); dbus_bool_t _dbus_auth_test (const char *test_data_dir); dbus_bool_t _dbus_md5_test (void); dbus_bool_t _dbus_sha_test (const char *test_data_dir); diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index b604a397..c5ce638f 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -226,7 +226,6 @@ init_global_locks (void) LOCK_ADDR (server_slots), LOCK_ADDR (message_slots), LOCK_ADDR (atomic), - LOCK_ADDR (message_handler), LOCK_ADDR (bus), LOCK_ADDR (shutdown_funcs), LOCK_ADDR (system_users) diff --git a/dbus/dbus.h b/dbus/dbus.h index 051cb5fa..99eee18c 100644 --- a/dbus/dbus.h +++ b/dbus/dbus.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include -- cgit From fdb114e5cce2790fd3c68cfa13113c7b59b83e4e Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 31 Aug 2003 17:26:22 +0000 Subject: 2003-08-31 Havoc Pennington * fix build with --disable-tests --- dbus/dbus-internals.c | 2 -- dbus/dbus-marshal.c | 6 ------ 2 files changed, 8 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index ccc11776..47a2b404 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -265,7 +265,6 @@ _dbus_strdup (const char *str) return copy; } -#ifdef DBUS_BUILD_TESTS /* memdup not used at the moment */ /** * Duplicates a block of memory. Returns * #NULL on failure. @@ -288,7 +287,6 @@ _dbus_memdup (const void *mem, return copy; } -#endif /** * Duplicates a string array. Result may be freed with diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 6343056e..5297cb67 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -1906,12 +1906,6 @@ validate_array_data (const DBusString *str, * returns #TRUE if a valid arg begins at "pos" * * @todo security: need to audit this function. - * - * @todo For array types that can't be invalid, we should not - * walk the whole array validating it. e.g. just skip all the - * int values in an int array. (maybe this is already done now -hp) - * - * @todo support DBUS_TYPE_OBJECT_PATH * * @param str a string * @param byte_order the byte order to use -- cgit From d021cfae6695f0f44102edf758abfc42e2f3c093 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 3 Sep 2003 02:08:25 +0000 Subject: 2003-09-01 Havoc Pennington * glib/dbus-gparser.c: implement * glib/dbus-gobject.c: start implementing skeletons support * configure.in: when disabling checks/assert, also define G_DISABLE_ASSERT and G_DISABLE_CHECKS --- dbus/dbus-marshal.c | 4 ++-- dbus/dbus-protocol.h | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 5297cb67..c542ee8b 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -1473,7 +1473,8 @@ _dbus_demarshal_string_array (const DBusString *str, #define VERBOSE_DECOMPOSE 0 /** - * Demarshals an object path. + * Demarshals an object path. A path of just "/" is + * represented as an empty vector of strings. * * @param str the string containing the data * @param byte_order the byte order @@ -1556,7 +1557,6 @@ _dbus_demarshal_object_path (const DBusString *str, i = j; } _dbus_assert (i == len); - _dbus_assert (retval[0] != NULL); *path = retval; if (path_len) diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index e56ab756..473a1051 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -87,6 +87,18 @@ extern "C" { #define DBUS_PATH_ORG_FREEDESKTOP_DBUS "/org/freedesktop/DBus" #define DBUS_PATH_ORG_FREEDESKTOP_LOCAL "/org/freedesktop/Local" +/* Interfaces, these #define don't do much other than + * catch typos at compile time + */ +#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus" +#define DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE "org.freedesktop.Introspectable" + +/* 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" + /* Service owner flags */ #define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1 #define DBUS_SERVICE_FLAG_REPLACE_EXISTING 0x2 @@ -101,17 +113,6 @@ extern "C" { #define DBUS_ACTIVATION_REPLY_ACTIVATED 0x0 #define DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE 0x1 -/* Interfaces, these #define don't do much other than - * catch typos at compile time - */ -#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" - #ifdef __cplusplus } #endif -- cgit From 666fe95480c14d7cbf5143b1a4e1bf0558403d4d Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 6 Sep 2003 18:21:00 +0000 Subject: 2003-09-06 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_register_fallback): add this (dbus_connection_register_object_path): make this not handle messages to paths below the given path --- dbus/dbus-connection.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- dbus/dbus-connection.h | 4 ++++ dbus/dbus-object-tree.c | 37 ++++++++++++++++++++++++++++--------- dbus/dbus-object-tree.h | 1 + 4 files changed, 76 insertions(+), 12 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 608634d2..b8e67c14 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -3049,8 +3049,8 @@ dbus_connection_remove_filter (DBusConnection *connection, } /** - * Registers a handler for a given subsection of the object hierarchy. - * The given vtable handles messages at or below the given path. + * Registers a handler for a given path in the object hierarchy. + * The given vtable handles messages sent to exactly the given path. * * * @param connection the connection @@ -3074,7 +3074,47 @@ dbus_connection_register_object_path (DBusConnection *connection, CONNECTION_LOCK (connection); - retval = _dbus_object_tree_register (connection->objects, path, vtable, + retval = _dbus_object_tree_register (connection->objects, + FALSE, + path, vtable, + user_data); + + CONNECTION_UNLOCK (connection); + + return retval; +} + +/** + * Registers a fallback handler for a given subsection of the object + * hierarchy. The given vtable handles messages at or below the given + * path. You can use this to establish a default message handling + * policy for a whole "subdirectory." + * + * + * @param connection the connection + * @param path #NULL-terminated array of path elements + * @param vtable the virtual table + * @param user_data data to pass to functions in the vtable + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_connection_register_fallback (DBusConnection *connection, + const char **path, + const DBusObjectPathVTable *vtable, + void *user_data) +{ + dbus_bool_t retval; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] != NULL, FALSE); + _dbus_return_val_if_fail (vtable != NULL, FALSE); + + CONNECTION_LOCK (connection); + + retval = _dbus_object_tree_register (connection->objects, + TRUE, + path, vtable, user_data); CONNECTION_UNLOCK (connection); diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index c5dee7f0..bbdbcda8 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -229,6 +229,10 @@ dbus_bool_t dbus_connection_register_object_path (DBusConnection const char **path, const DBusObjectPathVTable *vtable, void *user_data); +dbus_bool_t dbus_connection_register_fallback (DBusConnection *connection, + const char **path, + const DBusObjectPathVTable *vtable, + void *user_data); void dbus_connection_unregister_object_path (DBusConnection *connection, const char **path); diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 24e402a2..8430b323 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -71,6 +71,7 @@ struct DBusObjectSubtree DBusObjectSubtree **subtrees; int n_subtrees; unsigned int subtrees_sorted : 1; + unsigned int invoke_as_fallback : 1; char name[1]; /**< Allocated as large as necessary */ }; @@ -93,7 +94,8 @@ _dbus_object_tree_new (DBusConnection *connection) tree->root = _dbus_object_subtree_new ("/", NULL, NULL); if (tree->root == NULL) goto oom; - + tree->root->invoke_as_fallback = TRUE; + return tree; oom: @@ -221,7 +223,8 @@ find_subtree_recurse (DBusObjectSubtree *subtree, next = find_subtree_recurse (subtree->subtrees[i], &path[1], return_deepest_match, create_if_not_found, index_in_parent); - if (next == NULL) + if (next == NULL && + subtree->invoke_as_fallback) { #if VERBOSE_FIND _dbus_verbose (" no deeper match found, returning %s\n", @@ -293,7 +296,7 @@ find_subtree_recurse (DBusObjectSubtree *subtree, create_if_not_found, index_in_parent); } else - return return_deepest_match ? subtree : NULL; + return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; } static DBusObjectSubtree* @@ -339,6 +342,7 @@ ensure_subtree (DBusObjectTree *tree, * Registers a new subtree in the global object tree. * * @param tree the global object tree + * @param fallback #TRUE to handle messages to children of this path * @param path NULL-terminated array of path elements giving path to subtree * @param vtable the vtable used to traverse this subtree * @param user_data user data to pass to methods in the vtable @@ -346,6 +350,7 @@ ensure_subtree (DBusObjectTree *tree, */ dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, + dbus_bool_t fallback, const char **path, const DBusObjectPathVTable *vtable, void *user_data) @@ -360,17 +365,22 @@ _dbus_object_tree_register (DBusObjectTree *tree, if (subtree == NULL) return FALSE; +#ifndef DBUS_DISABLE_CHECKS if (subtree->message_function != NULL) { _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n", path[0] ? path[0] : "null"); return FALSE; } +#else + _dbus_assert (subtree->message_function == NULL); +#endif subtree->message_function = vtable->message_function; subtree->unregister_function = vtable->unregister_function; subtree->user_data = user_data; - + subtree->invoke_as_fallback = fallback != FALSE; + return TRUE; } @@ -395,6 +405,7 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, subtree = find_subtree (tree, path, &i); +#ifndef DBUS_DISABLE_CHECKS if (subtree == NULL) { _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", @@ -402,6 +413,9 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, path[1] ? path[1] : "null"); return; } +#else + _dbus_assert (subtree != NULL); +#endif _dbus_assert (subtree->parent == NULL || (i >= 0 && subtree->parent->subtrees[i] == subtree)); @@ -523,7 +537,7 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, DBusList *link; DBusHandlerResult result; DBusObjectSubtree *subtree; - + #if 0 _dbus_verbose ("Dispatch of message by object path\n"); #endif @@ -540,10 +554,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, _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 */ subtree = find_handler (tree, (const char**) path); - + /* Build a list of all paths that cover the path in the message */ list = NULL; @@ -884,7 +898,7 @@ do_register (DBusObjectTree *tree, tree_test_data[i].handler_unregistered = FALSE; tree_test_data[i].path = path; - if (!_dbus_object_tree_register (tree, path, + if (!_dbus_object_tree_register (tree, TRUE, path, &vtable, &tree_test_data[i])) return FALSE; @@ -1269,7 +1283,12 @@ object_tree_test_iteration (void *data) out: if (tree) - _dbus_object_tree_unref (tree); + { + /* test ref */ + _dbus_object_tree_ref (tree); + _dbus_object_tree_unref (tree); + _dbus_object_tree_unref (tree); + } return TRUE; } diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h index 5d44bbe2..21d8b5f1 100644 --- a/dbus/dbus-object-tree.h +++ b/dbus/dbus-object-tree.h @@ -34,6 +34,7 @@ void _dbus_object_tree_ref (DBusObjectTree *tree); void _dbus_object_tree_unref (DBusObjectTree *tree); dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, + dbus_bool_t fallback, const char **path, const DBusObjectPathVTable *vtable, void *user_data); -- cgit From 85ab0327d82e4945ad16630e583d8cc68df25a90 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 7 Sep 2003 23:04:54 +0000 Subject: 2003-09-07 Havoc Pennington * Make Doxygen contented. --- dbus/dbus-address.c | 27 +++++++++---- dbus/dbus-auth.c | 40 +++++++++++++------- dbus/dbus-connection.c | 35 +++++++++++------ dbus/dbus-connection.h | 16 +++++--- dbus/dbus-dataslot.h | 10 +++++ dbus/dbus-errors.c | 84 +++++++++++++++++++++++------------------ dbus/dbus-errors.h | 3 ++ dbus/dbus-hash.c | 1 + dbus/dbus-hash.h | 18 ++++----- dbus/dbus-internals.c | 1 + dbus/dbus-keyring.c | 3 ++ dbus/dbus-mainloop.c | 3 ++ dbus/dbus-mainloop.h | 5 +++ dbus/dbus-marshal.c | 11 ++++-- dbus/dbus-md5.h | 9 +++-- dbus/dbus-message-builder.c | 5 ++- dbus/dbus-message.c | 10 ++++- dbus/dbus-message.h | 33 ++++++++-------- dbus/dbus-object-tree.c | 60 +++++++++++++++++++++-------- dbus/dbus-server-protected.h | 6 +++ dbus/dbus-sha.h | 5 ++- dbus/dbus-spawn.c | 29 +++++++------- dbus/dbus-string.c | 2 +- dbus/dbus-string.h | 3 ++ dbus/dbus-sysdeps.c | 5 ++- dbus/dbus-sysdeps.h | 50 ++++++++++++++++-------- dbus/dbus-threads.h | 46 +++++++++++----------- dbus/dbus-timeout.c | 3 ++ dbus/dbus-transport-protected.h | 10 +++++ dbus/dbus-userdb.c | 13 ++++--- dbus/dbus-watch.c | 3 ++ 31 files changed, 369 insertions(+), 180 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-address.c b/dbus/dbus-address.c index 89dac41e..97af49fd 100644 --- a/dbus/dbus-address.c +++ b/dbus/dbus-address.c @@ -28,20 +28,26 @@ #include "dbus-string.h" /** - * @defgroup DBusAddress Address parsing - * @ingroup DBus - * @brief Parsing addresses of D-BUS servers. + * @defgroup DBusAddressInternals Address parsing + * @ingroup DBusInternals + * @brief Implementation of parsing addresses of D-BUS servers. * * @{ */ + +/** + * Internals of DBusAddressEntry + */ struct DBusAddressEntry { - DBusString method; + DBusString method; /**< The address type (unix, tcp, etc.) */ - DBusList *keys; - DBusList *values; + DBusList *keys; /**< List of keys */ + DBusList *values; /**< List of values */ }; +/** @} */ /* End of internals */ + static void dbus_address_entry_free (DBusAddressEntry *entry) { @@ -72,6 +78,13 @@ dbus_address_entry_free (DBusAddressEntry *entry) dbus_free (entry); } +/** + * @defgroup DBusAddress Address parsing + * @ingroup DBus + * @brief Parsing addresses of D-BUS servers. + * + * @{ + */ /** * Frees a #NULL-terminated array of address entries. @@ -372,7 +385,7 @@ dbus_parse_address (const char *address, } -/** @} */ +/** @} */ /* End of public API */ #ifdef DBUS_BUILD_TESTS #include "dbus-test.h" diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 95910445..90c72fd5 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -73,10 +73,13 @@ typedef dbus_bool_t (* DBusProcessAuthCommandFunction) (DBusAuth *auth, const DBusString *command, const DBusString *args); +/** + * Handler for a given auth protocol command + */ typedef struct { - const char *command; - DBusProcessAuthCommandFunction func; + const char *command; /**< Name of the command */ + DBusProcessAuthCommandFunction func; /**< Function to handle the command */ } DBusAuthCommandHandler; /** @@ -111,18 +114,21 @@ typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth, */ typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth); +/** + * Virtual table representing a particular auth mechanism. + */ typedef struct { - const char *mechanism; - DBusAuthDataFunction server_data_func; - DBusAuthEncodeFunction server_encode_func; - DBusAuthDecodeFunction server_decode_func; - DBusAuthShutdownFunction server_shutdown_func; - DBusInitialResponseFunction client_initial_response_func; - DBusAuthDataFunction client_data_func; - DBusAuthEncodeFunction client_encode_func; - DBusAuthDecodeFunction client_decode_func; - DBusAuthShutdownFunction client_shutdown_func; + const char *mechanism; /**< Name of the mechanism */ + DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */ + DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */ + DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */ + DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */ + DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */ + DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */ + DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */ + DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */ + DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */ } DBusAuthMechanismHandler; /** @@ -172,17 +178,23 @@ struct DBusAuth unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */ }; +/** + * "Subclass" of DBusAuth for client side + */ typedef struct { - DBusAuth base; + DBusAuth base; /**< Parent class */ DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */ } DBusAuthClient; +/** + * "Subclass" of DBusAuth for server side. + */ typedef struct { - DBusAuth base; + DBusAuth base; /**< Parent class */ int failures; /**< Number of times client has been rejected */ int max_failures; /**< Number of times we reject before disconnect */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index b8e67c14..bab6ffd8 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -124,14 +124,31 @@ * @{ */ +/** + * Internal struct representing a message filter function + */ typedef struct DBusMessageFilter DBusMessageFilter; +/** + * Internal struct representing a message filter function + */ struct DBusMessageFilter { - DBusAtomic refcount; - DBusHandleMessageFunction function; - void *user_data; - DBusFreeFunction free_user_data_function; + DBusAtomic refcount; /**< Reference count */ + DBusHandleMessageFunction function; /**< Function to call to filter */ + void *user_data; /**< User data for the function */ + DBusFreeFunction free_user_data_function; /**< Function to free the user data */ +}; + + +/** + * Internals of DBusPreallocatedSend + */ +struct DBusPreallocatedSend +{ + DBusConnection *connection; /**< Connection we'd send the message to */ + DBusList *queue_link; /**< Preallocated link in the queue */ + DBusList *counter_link; /**< Preallocated link in the resource counter */ }; static dbus_bool_t _dbus_modify_sigpipe = TRUE; @@ -1339,13 +1356,6 @@ dbus_connection_get_is_authenticated (DBusConnection *connection) return res; } -struct DBusPreallocatedSend -{ - DBusConnection *connection; - DBusList *queue_link; - DBusList *counter_link; -}; - static DBusPreallocatedSend* _dbus_connection_preallocate_send_unlocked (DBusConnection *connection) { @@ -2992,7 +3002,8 @@ dbus_connection_add_filter (DBusConnection *connection, * instance). * * @param connection the connection - * @param handler the handler to remove + * @param function the handler to remove + * @param user_data user data for the handler to remove * */ void diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index bbdbcda8..abc88056 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -214,15 +214,19 @@ typedef DBusHandlerResult (* DBusObjectPathMessageFunction) (DBusConnection DBusMessage *message, void *user_data); +/** + * Virtual table that must be implemented to handle a portion of the + * object path hierarchy. + */ struct DBusObjectPathVTable { - DBusObjectPathUnregisterFunction unregister_function; - DBusObjectPathMessageFunction message_function; + DBusObjectPathUnregisterFunction unregister_function; /**< Function to unregister this handler */ + DBusObjectPathMessageFunction message_function; /**< Function to handle messages */ - void (* dbus_internal_pad1) (void *); - void (* dbus_internal_pad2) (void *); - void (* dbus_internal_pad3) (void *); - void (* dbus_internal_pad4) (void *); + void (* dbus_internal_pad1) (void *); /**< Reserved for future expansion */ + void (* dbus_internal_pad2) (void *); /**< Reserved for future expansion */ + void (* dbus_internal_pad3) (void *); /**< Reserved for future expansion */ + void (* dbus_internal_pad4) (void *); /**< Reserved for future expansion */ }; dbus_bool_t dbus_connection_register_object_path (DBusConnection *connection, diff --git a/dbus/dbus-dataslot.h b/dbus/dbus-dataslot.h index 6f591eb5..c4a914b4 100644 --- a/dbus/dbus-dataslot.h +++ b/dbus/dbus-dataslot.h @@ -40,12 +40,18 @@ struct DBusDataSlot }; typedef struct DBusAllocatedSlot DBusAllocatedSlot; + +/** An allocated slot for storing data + */ struct DBusAllocatedSlot { dbus_int32_t slot_id; /**< ID of this slot */ int refcount; /**< Number of uses of the slot */ }; +/** + * An allocator that tracks a set of slot IDs. + */ struct DBusDataSlotAllocator { DBusAllocatedSlot *allocated_slots; /**< Allocated slots */ @@ -54,6 +60,10 @@ struct DBusDataSlotAllocator DBusMutex *lock; /**< thread lock */ }; +/** + * Data structure that stores the actual user data set at a given + * slot. + */ struct DBusDataSlotList { DBusDataSlot *slots; /**< Data slots */ diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c index 82e48025..f7b2f740 100644 --- a/dbus/dbus-errors.c +++ b/dbus/dbus-errors.c @@ -28,48 +28,21 @@ #include /** - * @defgroup DBusErrors Error reporting - * @ingroup DBus - * @brief Error reporting - * - * Types and functions related to reporting errors. - * - * - * In essence D-BUS error reporting works as follows: - * - * @code - * DBusError error; - * dbus_error_init (&error); - * dbus_some_function (arg1, arg2, &error); - * if (dbus_error_is_set (&error)) - * { - * fprintf (stderr, "an error occurred: %s\n", error.message); - * dbus_error_free (&error); - * } - * @endcode - * - * There are some rules. An error passed to a D-BUS function must - * always be unset; you can't pass in an error that's already set. If - * a function has a return code indicating whether an error occurred, - * and also a #DBusError parameter, then the error will always be set - * if and only if the return code indicates an error occurred. i.e. - * the return code and the error are never going to disagree. - * - * An error only needs to be freed if it's been set, not if - * it's merely been initialized. - * - * You can check the specific error that occurred using - * dbus_error_has_name(). - * + * @defgroup DBusErrorInternals Error reporting internals + * @ingroup DBusInternals + * @brief Error reporting internals * @{ */ - + +/** + * Internals of DBusError + */ typedef struct { const char *name; /**< error name */ char *message; /**< error message */ - unsigned int const_message : 1; /** Message is not owned by DBusError */ + unsigned int const_message : 1; /**< Message is not owned by DBusError */ unsigned int dummy2 : 1; /**< placeholder */ unsigned int dummy3 : 1; /**< placeholder */ @@ -127,6 +100,45 @@ message_from_error (const char *error) return error; } +/** @} */ /* End of internals */ + +/** + * @defgroup DBusErrors Error reporting + * @ingroup DBus + * @brief Error reporting + * + * Types and functions related to reporting errors. + * + * + * In essence D-BUS error reporting works as follows: + * + * @code + * DBusError error; + * dbus_error_init (&error); + * dbus_some_function (arg1, arg2, &error); + * if (dbus_error_is_set (&error)) + * { + * fprintf (stderr, "an error occurred: %s\n", error.message); + * dbus_error_free (&error); + * } + * @endcode + * + * There are some rules. An error passed to a D-BUS function must + * always be unset; you can't pass in an error that's already set. If + * a function has a return code indicating whether an error occurred, + * and also a #DBusError parameter, then the error will always be set + * if and only if the return code indicates an error occurred. i.e. + * the return code and the error are never going to disagree. + * + * An error only needs to be freed if it's been set, not if + * it's merely been initialized. + * + * You can check the specific error that occurred using + * dbus_error_has_name(). + * + * @{ + */ + /** * Initializes a DBusError structure. Does not allocate * any memory; the error only needs to be freed @@ -358,4 +370,4 @@ dbus_set_error (DBusError *error, dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL); } -/** @} */ +/** @} */ /* End public API */ diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h index ca398a0b..ad4801c9 100644 --- a/dbus/dbus-errors.h +++ b/dbus/dbus-errors.h @@ -35,6 +35,9 @@ DBUS_BEGIN_DECLS; typedef struct DBusError DBusError; +/** + * Object representing an exception. + */ struct DBusError { const char *name; /**< error name */ diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c index 044dc534..d35087b4 100644 --- a/dbus/dbus-hash.c +++ b/dbus/dbus-hash.c @@ -865,6 +865,7 @@ two_strings_hash (const char *str) return h; } +/** Key comparison function */ typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b); static DBusHashEntry* diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h index 25b81dd6..5e7515f9 100644 --- a/dbus/dbus-hash.h +++ b/dbus/dbus-hash.h @@ -29,17 +29,17 @@ DBUS_BEGIN_DECLS; -/* The iterator is on the stack, but its real fields are - * hidden privately. +/** Hash iterator object. The iterator is on the stack, but its real + * fields are hidden privately. */ struct DBusHashIter { - void *dummy1; - void *dummy2; - void *dummy3; - void *dummy4; - int dummy5; - int dummy6; + void *dummy1; /**< Do not use. */ + void *dummy2; /**< Do not use. */ + void *dummy3; /**< Do not use. */ + void *dummy4; /**< Do not use. */ + int dummy5; /**< Do not use. */ + int dummy6; /**< Do not use. */ }; typedef struct DBusHashTable DBusHashTable; @@ -53,7 +53,7 @@ typedef struct DBusHashIter DBusHashIter; typedef enum { 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_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. */ diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 47a2b404..463e62e1 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -390,6 +390,7 @@ _dbus_type_to_string (int type) } #ifndef DBUS_DISABLE_CHECKS +/** String used in _dbus_return_if_fail macro */ const char _dbus_return_if_fail_warning_format[] = "Arguments to %s were incorrect, assertion \"%s\" failed in file %s line %d.\n" "This is normally a bug in some application using the D-BUS library.\n"; diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c index b5974af0..e091d801 100644 --- a/dbus/dbus-keyring.c +++ b/dbus/dbus-keyring.c @@ -85,6 +85,9 @@ #define MAX_KEYS_IN_FILE 256 #endif +/** + * A single key from the cookie file + */ typedef struct { dbus_int32_t id; /**< identifier used to refer to the key */ diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c index 51eb7b0d..f3b68272 100644 --- a/dbus/dbus-mainloop.c +++ b/dbus/dbus-mainloop.c @@ -23,6 +23,8 @@ #include "dbus-mainloop.h" +#ifndef DOXYGEN_SHOULD_SKIP_THIS + #include #include @@ -876,3 +878,4 @@ _dbus_wait_for_memory (void) _dbus_sleep_milliseconds (_dbus_get_oom_wait ()); } +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/dbus/dbus-mainloop.h b/dbus/dbus-mainloop.h index ac5731f5..8a3cde13 100644 --- a/dbus/dbus-mainloop.h +++ b/dbus/dbus-mainloop.h @@ -24,6 +24,8 @@ #ifndef DBUS_MAINLOOP_H #define DBUS_MAINLOOP_H +#ifndef DOXYGEN_SHOULD_SKIP_THIS + #include typedef struct DBusLoop DBusLoop; @@ -68,4 +70,7 @@ dbus_bool_t _dbus_loop_dispatch (DBusLoop *loop); int _dbus_get_oom_wait (void); void _dbus_wait_for_memory (void); +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + #endif /* DBUS_MAINLOOP_H */ + diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index c542ee8b..3d6184e9 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -73,13 +73,17 @@ swap_bytes (unsigned char *data, } #endif /* !DBUS_HAVE_INT64 */ +/** + * Union used to manipulate 8 bytes as if they + * were various types. + */ typedef union { #ifdef DBUS_HAVE_INT64 - dbus_int64_t s; - dbus_uint64_t u; + dbus_int64_t s; /**< 64-bit integer */ + dbus_uint64_t u; /**< 64-bit unsinged integer */ #endif - double d; + double d; /**< double */ } DBusOctets8; static DBusOctets8 @@ -1470,6 +1474,7 @@ _dbus_demarshal_string_array (const DBusString *str, return FALSE; } +/** Set to 1 to get a bunch of spew about disassembling the path string */ #define VERBOSE_DECOMPOSE 0 /** diff --git a/dbus/dbus-md5.h b/dbus/dbus-md5.h index 63fc62e8..e31711dd 100644 --- a/dbus/dbus-md5.h +++ b/dbus/dbus-md5.h @@ -31,11 +31,14 @@ DBUS_BEGIN_DECLS; typedef struct DBusMD5Context DBusMD5Context; +/** + * A context used to store the state of the MD5 algorithm + */ struct DBusMD5Context { - dbus_uint32_t count[2]; /* message length in bits, lsw first */ - dbus_uint32_t abcd[4]; /* digest buffer */ - unsigned char buf[64]; /* accumulate block */ + dbus_uint32_t count[2]; /**< message length in bits, lsw first */ + dbus_uint32_t abcd[4]; /**< digest buffer */ + unsigned char buf[64]; /**< accumulate block */ }; void _dbus_md5_init (DBusMD5Context *context); diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 6d162310..52c78227 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -40,9 +40,12 @@ * @{ */ +/** + * Saved length + */ typedef struct { - DBusString name; + DBusString name; /**< Name of the length */ int start; /**< Calculate length since here */ int length; /**< length to write */ int offset; /**< where to write it into the data */ diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 090bdfc7..d62cbf4f 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -72,6 +72,9 @@ static dbus_bool_t field_is_named[FIELD_LAST] = TRUE /* FIELD_REPLY_SERIAL */ }; +/** + * Cached information about a header field in the message + */ typedef struct { int offset; /**< Offset to start of field (location of name of field @@ -79,9 +82,13 @@ typedef struct */ } HeaderField; +/** Offset to byte order from start of header */ #define BYTE_ORDER_OFFSET 0 +/** Offset to type from start of header */ #define TYPE_OFFSET 1 +/** Offset to flags from start of header */ #define FLAGS_OFFSET 2 +/** Offset to version from start of header */ #define VERSION_OFFSET 3 /** @@ -1161,6 +1168,7 @@ dbus_message_new_method_return (DBusMessage *method_call) * A signal is identified by its originating interface, and * the name of the signal. * + * @param path the path to the object emitting 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() @@ -1576,7 +1584,7 @@ dbus_message_get_member (DBusMessage *message) * The name is fully-qualified (namespaced). * * @param message the message - * @param name the name + * @param error_name the name * @returns #FALSE if not enough memory */ dbus_bool_t diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index def65379..888fe862 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -39,22 +39,25 @@ DBUS_BEGIN_DECLS; typedef struct DBusMessage DBusMessage; typedef struct DBusMessageIter DBusMessageIter; +/** + * DBusMessageIter struct; contains no public fields + */ struct DBusMessageIter -{ - void *dummy1; - void *dummy2; - dbus_uint32_t dummy3; - int dummy4; - int dummy5; - int dummy6; - int dummy7; - int dummy8; - int dummy9; - int dummy10; - int dummy11; - int pad1; - int pad2; - void *pad3; +{ + void *dummy1; /**< Don't use this */ + void *dummy2; /**< Don't use this */ + dbus_uint32_t dummy3; /**< Don't use this */ + int dummy4; /**< Don't use this */ + int dummy5; /**< Don't use this */ + int dummy6; /**< Don't use this */ + int dummy7; /**< Don't use this */ + int dummy8; /**< Don't use this */ + int dummy9; /**< Don't use this */ + int dummy10; /**< Don't use this */ + int dummy11; /**< Don't use this */ + int pad1; /**< Don't use this */ + int pad2; /**< Don't use this */ + void *pad3; /**< Don't use this */ }; DBusMessage* dbus_message_new (int message_type); diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 8430b323..9922dec4 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -45,6 +45,7 @@ * @{ */ +/** Subnode of the object hierarchy */ typedef struct DBusObjectSubtree DBusObjectSubtree; static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, @@ -53,28 +54,43 @@ static DBusObjectSubtree* _dbus_object_subtree_new (const char static void _dbus_object_subtree_ref (DBusObjectSubtree *subtree); static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); +/** + * Internals of DBusObjectTree + */ struct DBusObjectTree { - int refcount; - DBusConnection *connection; + int refcount; /**< Reference count */ + DBusConnection *connection; /**< Connection this tree belongs to */ - DBusObjectSubtree *root; + DBusObjectSubtree *root; /**< Root of the tree ("/" node) */ }; +/** + * Struct representing a single registered subtree handler, or node + * that's a parent of a registered subtree handler. If + * message_function != NULL there's actually a handler at this node. + */ struct DBusObjectSubtree { - DBusAtomic refcount; - DBusObjectSubtree *parent; - DBusObjectPathUnregisterFunction unregister_function; - DBusObjectPathMessageFunction message_function; - void *user_data; - DBusObjectSubtree **subtrees; - int n_subtrees; - unsigned int subtrees_sorted : 1; - unsigned int invoke_as_fallback : 1; + DBusAtomic refcount; /**< Reference count */ + DBusObjectSubtree *parent; /**< Parent node */ + DBusObjectPathUnregisterFunction unregister_function; /**< Function to call on unregister */ + DBusObjectPathMessageFunction message_function; /**< Function to handle messages */ + void *user_data; /**< Data for functions */ + DBusObjectSubtree **subtrees; /**< Child nodes */ + int n_subtrees; /**< Number of child nodes */ + unsigned int subtrees_sorted : 1; /**< Whether children are sorted */ + unsigned int invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */ char name[1]; /**< Allocated as large as necessary */ }; +/** + * Creates a new object tree, representing a mapping from paths + * to handler vtables. + * + * @param connection the connection this tree belongs to + * @returns the new tree or #NULL if no memory + */ DBusObjectTree* _dbus_object_tree_new (DBusConnection *connection) { @@ -107,6 +123,10 @@ _dbus_object_tree_new (DBusConnection *connection) return NULL; } +/** + * Increment the reference count + * @param tree the object tree + */ void _dbus_object_tree_ref (DBusObjectTree *tree) { @@ -115,6 +135,10 @@ _dbus_object_tree_ref (DBusObjectTree *tree) tree->refcount += 1; } +/** + * Decrement the reference count + * @param tree the object tree + */ void _dbus_object_tree_unref (DBusObjectTree *tree) { @@ -160,6 +184,9 @@ ensure_sorted (DBusObjectSubtree *subtree) } } +/** Set to 1 to get a bunch of debug spew about finding the + * subtree nodes + */ #define VERBOSE_FIND 0 static DBusObjectSubtree* @@ -855,11 +882,14 @@ spew_tree (DBusObjectTree *tree) spew_subtree_recurse (tree->root, 0); } +/** + * Callback data used in tests + */ typedef struct { - const char **path; - dbus_bool_t message_handled; - dbus_bool_t handler_unregistered; + const char **path; /**< Path */ + dbus_bool_t message_handled; /**< Gets set to true if message handler called */ + dbus_bool_t handler_unregistered; /**< gets set to true if handler is unregistered */ } TreeTestData; diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h index a3774c31..317805f5 100644 --- a/dbus/dbus-server-protected.h +++ b/dbus/dbus-server-protected.h @@ -34,6 +34,9 @@ DBUS_BEGIN_DECLS; typedef struct DBusServerVTable DBusServerVTable; +/** + * Virtual table to be implemented by all server "subclasses" + */ struct DBusServerVTable { void (* finalize) (DBusServer *server); @@ -43,6 +46,9 @@ struct DBusServerVTable /**< Disconnect this server. */ }; +/** + * Internals of DBusServer object + */ struct DBusServer { int refcount; /**< Reference count. */ diff --git a/dbus/dbus-sha.h b/dbus/dbus-sha.h index 7f793844..0a48d197 100644 --- a/dbus/dbus-sha.h +++ b/dbus/dbus-sha.h @@ -31,11 +31,14 @@ DBUS_BEGIN_DECLS; typedef struct DBusSHAContext DBusSHAContext; +/** + * Struct storing state of the SHA algorithm + */ struct DBusSHAContext { dbus_uint32_t digest[5]; /**< Message digest */ dbus_uint32_t count_lo; /**< 64-bit bit count */ - dbus_uint32_t count_hi; + dbus_uint32_t count_hi; /**< No clue */ dbus_uint32_t data[16]; /**< SHA data buffer */ }; diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c index d4015561..604b9e7c 100644 --- a/dbus/dbus-spawn.c +++ b/dbus/dbus-spawn.c @@ -176,28 +176,31 @@ enum CHILD_PID /* Followed by pid_t */ }; +/** + * Babysitter implementation details + */ struct DBusBabysitter { - int refcount; + int refcount; /**< Reference count */ char *executable; /**< executable name to use in error messages */ - int socket_to_babysitter; - int error_pipe_from_child; + int socket_to_babysitter; /**< Connection to the babysitter process */ + int error_pipe_from_child; /**< Connection to the process that does the exec() */ - pid_t sitter_pid; - pid_t grandchild_pid; + pid_t sitter_pid; /**< PID Of the babysitter */ + pid_t grandchild_pid; /**< PID of the grandchild */ - DBusWatchList *watches; + DBusWatchList *watches; /**< Watches */ - DBusWatch *error_watch; - DBusWatch *sitter_watch; + DBusWatch *error_watch; /**< Error pipe watch */ + DBusWatch *sitter_watch; /**< Sitter pipe watch */ - int errnum; - int status; - unsigned int have_child_status : 1; - unsigned int have_fork_errnum : 1; - unsigned int have_exec_errnum : 1; + int errnum; /**< Error number */ + int status; /**< Exit status code */ + unsigned int have_child_status : 1; /**< True if child status has been reaped */ + unsigned int have_fork_errnum : 1; /**< True if we have an error code from fork() */ + unsigned int have_exec_errnum : 1; /**< True if we have an error code from exec() */ }; static DBusBabysitter* diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 54dbdb7f..40363686 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -1807,7 +1807,7 @@ _dbus_string_skip_white (const DBusString *str, } /** - * Assigns a newline-terminated or \r\n-terminated line from the front + * Assigns a newline-terminated or \\r\\n-terminated line from the front * of the string to the given dest string. The dest string's previous * contents are deleted. If the source string contains no newline, * moves the entire source string to the dest string. diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 761ad487..70e83b33 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -34,6 +34,9 @@ DBUS_BEGIN_DECLS; +/** + * DBusString object + */ struct DBusString { void *dummy1; /**< placeholder */ diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 5311b202..c3ddf8cd 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -2515,9 +2515,12 @@ _dbus_path_is_absolute (const DBusString *filename) return FALSE; } +/** + * Internals of directory iterator + */ struct DBusDirIter { - DIR *d; + DIR *d; /**< The DIR* from opendir() */ }; diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index bfdcfb0a..363f665d 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -97,12 +97,14 @@ typedef unsigned long dbus_gid_t; #define DBUS_UID_FORMAT "%lu" #define DBUS_GID_FORMAT "%lu" +/** + * Struct representing socket credentials + */ typedef struct { - /* Set to DBUS_PID_UNSET etc. if not available */ - dbus_pid_t pid; - dbus_uid_t uid; - dbus_gid_t gid; + dbus_pid_t pid; /**< process ID or DBUS_PID_UNSET */ + dbus_uid_t uid; /**< user ID or DBUS_UID_UNSET */ + dbus_gid_t gid; /**< group ID or DBUS_GID_UNSET */ } DBusCredentials; int _dbus_connect_unix_socket (const char *path, @@ -135,6 +137,9 @@ dbus_bool_t _dbus_credentials_match (const DBusCredentials *expec typedef struct DBusUserInfo DBusUserInfo; typedef struct DBusGroupInfo DBusGroupInfo; +/** + * Information about a UNIX user + */ struct DBusUserInfo { dbus_uid_t uid; /**< UID */ @@ -145,6 +150,9 @@ struct DBusUserInfo char *homedir; /**< Home directory */ }; +/** + * Information about a UNIX group + */ struct DBusGroupInfo { dbus_gid_t gid; /**< GID */ @@ -173,9 +181,13 @@ dbus_uid_t _dbus_getuid (void); dbus_gid_t _dbus_getgid (void); typedef struct DBusAtomic DBusAtomic; + +/** + * An atomic integer. + */ struct DBusAtomic { - volatile dbus_int32_t value; + volatile dbus_int32_t value; /**< Value of the atomic integer. */ }; dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic); @@ -188,11 +200,14 @@ dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic); #define _DBUS_POLLHUP 0x0010 /* Hung up */ #define _DBUS_POLLNVAL 0x0020 /* Invalid request: fd not open */ +/** + * A portable struct pollfd wrapper. + */ typedef struct { - int fd; - short events; - short revents; + int fd; /**< File descriptor */ + short events; /**< Events to poll for */ + short revents; /**< Events that occurred */ } DBusPollFD; int _dbus_poll (DBusPollFD *fds, @@ -249,16 +264,19 @@ void _dbus_fd_set_close_on_exec (int fd); void _dbus_exit (int code) _DBUS_GNUC_NORETURN; +/** + * Portable struct with stat() results + */ typedef struct { - unsigned long mode; - unsigned long nlink; - dbus_uid_t uid; - dbus_gid_t gid; - unsigned long size; - unsigned long atime; - unsigned long mtime; - unsigned long ctime; + unsigned long mode; /**< File mode */ + unsigned long nlink; /**< Number of hard links */ + dbus_uid_t uid; /**< User owning file */ + dbus_gid_t gid; /**< Group owning file */ + unsigned long size; /**< Size of file */ + unsigned long atime; /**< Access time */ + unsigned long mtime; /**< Modify time */ + unsigned long ctime; /**< Creation time */ } DBusStat; dbus_bool_t _dbus_stat (const DBusString *filename, diff --git a/dbus/dbus-threads.h b/dbus/dbus-threads.h index 0dcb1040..dea969a2 100644 --- a/dbus/dbus-threads.h +++ b/dbus/dbus-threads.h @@ -66,30 +66,34 @@ typedef enum DBUS_THREAD_FUNCTIONS_ALL_MASK = (1 << 10) - 1 } DBusThreadFunctionsMask; +/** + * Functions that must be implemented to make the D-BUS + * library thread-aware. + */ typedef struct { - unsigned int mask; - - DBusMutexNewFunction mutex_new; - DBusMutexFreeFunction mutex_free; - DBusMutexLockFunction mutex_lock; - DBusMutexUnlockFunction mutex_unlock; - - DBusCondVarNewFunction condvar_new; - DBusCondVarFreeFunction condvar_free; - DBusCondVarWaitFunction condvar_wait; - DBusCondVarWaitTimeoutFunction condvar_wait_timeout; - DBusCondVarWakeOneFunction condvar_wake_one; - DBusCondVarWakeAllFunction condvar_wake_all; + unsigned int mask; /**< Mask indicating which functions are present. */ + + DBusMutexNewFunction mutex_new; /**< Function to create a mutex */ + DBusMutexFreeFunction mutex_free; /**< Function to free a mutex */ + DBusMutexLockFunction mutex_lock; /**< Function to lock a mutex */ + DBusMutexUnlockFunction mutex_unlock; /**< Function to unlock a mutex */ + + DBusCondVarNewFunction condvar_new; /**< Function to create a condition variable */ + DBusCondVarFreeFunction condvar_free; /**< Function to free a condition variable */ + DBusCondVarWaitFunction condvar_wait; /**< Function to wait on a condition */ + DBusCondVarWaitTimeoutFunction condvar_wait_timeout; /**< Function to wait on a condition with a timeout */ + DBusCondVarWakeOneFunction condvar_wake_one; /**< Function to wake one thread waiting on the condition */ + DBusCondVarWakeAllFunction condvar_wake_all; /**< Function to wake all threads waiting on the condition */ - void (* padding1) (void); - void (* padding2) (void); - void (* padding3) (void); - void (* padding4) (void); - void (* padding5) (void); - void (* padding6) (void); - void (* padding7) (void); - void (* padding8) (void); + void (* padding1) (void); /**< Reserved for future expansion */ + void (* padding2) (void); /**< Reserved for future expansion */ + void (* padding3) (void); /**< Reserved for future expansion */ + void (* padding4) (void); /**< Reserved for future expansion */ + void (* padding5) (void); /**< Reserved for future expansion */ + void (* padding6) (void); /**< Reserved for future expansion */ + void (* padding7) (void); /**< Reserved for future expansion */ + void (* padding8) (void); /**< Reserved for future expansion */ } DBusThreadFunctions; diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c index 289d6347..b15089db 100644 --- a/dbus/dbus-timeout.c +++ b/dbus/dbus-timeout.c @@ -33,6 +33,9 @@ * @{ */ +/** + * Internals of DBusTimeout + */ struct DBusTimeout { int refcount; /**< Reference count */ diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h index 1c5b4208..d4d20957 100644 --- a/dbus/dbus-transport-protected.h +++ b/dbus/dbus-transport-protected.h @@ -34,6 +34,10 @@ DBUS_BEGIN_DECLS; typedef struct DBusTransportVTable DBusTransportVTable; +/** + * The virtual table that must be implemented to + * create a new kind of transport. + */ struct DBusTransportVTable { void (* finalize) (DBusTransport *transport); @@ -69,6 +73,12 @@ struct DBusTransportVTable /**< Outstanding messages counter changed */ }; +/** + * Object representing a transport such as a socket. + * A transport can shuttle messages from point A to point B, + * and is the backend for a #DBusConnection. + * + */ struct DBusTransport { int refcount; /**< Reference count. */ diff --git a/dbus/dbus-userdb.c b/dbus/dbus-userdb.c index 4a7b7488..95f13981 100644 --- a/dbus/dbus-userdb.c +++ b/dbus/dbus-userdb.c @@ -26,14 +26,17 @@ #include "dbus-internals.h" #include +/** + * Internals of DBusUserDatabase + */ struct DBusUserDatabase { - int refcount; + int refcount; /**< Reference count */ - DBusHashTable *users; - DBusHashTable *groups; - DBusHashTable *users_by_name; - DBusHashTable *groups_by_name; + DBusHashTable *users; /**< Users in the database by UID */ + DBusHashTable *groups; /**< Groups in the database by GID */ + DBusHashTable *users_by_name; /**< Users in the database by name */ + DBusHashTable *groups_by_name; /**< Groups in the database by name */ }; static void diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c index 5b59e8c8..f212090a 100644 --- a/dbus/dbus-watch.c +++ b/dbus/dbus-watch.c @@ -33,6 +33,9 @@ * @{ */ +/** + * Implementation of DBusWatch + */ struct DBusWatch { int refcount; /**< Reference count */ -- cgit From 583994cb3b7f5562fb7b8c37b4cb0d5af78e4ce2 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 17 Sep 2003 03:52:07 +0000 Subject: 2003-09-15 Havoc Pennington * dbus/dbus-pending-call.c: add the get/set object data boilerplate as for DBusConnection, etc. Use generic object data for the notify callback. * glib/dbus-gparser.c (parse_node): parse child nodes * tools/dbus-viewer.c: more hacking on the dbus-viewer * glib/dbus-gutils.c (_dbus_gutils_split_path): add a file to contain functions shared between the convenience lib and the installed lib * glib/Makefile.am (libdbus_glib_1_la_LDFLAGS): add -export-symbols-regex to the GLib library * dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock): fix the locking in here, and add a default handler for Introspect() that just returns sub-nodes. 2003-09-14 Havoc Pennington * glib/dbus-gthread.c (dbus_g_thread_init): rename to make g_foo rather than gfoo consistent * glib/dbus-gproxy.h: delete for now, move contents to dbus-glib.h, because the include files don't work right since we aren't in the dbus/ subdir. * glib/dbus-gproxy.c (dbus_gproxy_send): finish implementing (dbus_gproxy_end_call): finish (dbus_gproxy_begin_call): finish * glib/dbus-gmain.c (dbus_set_g_error): new * glib/dbus-gobject.c (handle_introspect): include information about child nodes in the introspection * dbus/dbus-connection.c (dbus_connection_list_registered): new function to help in implementation of introspection * dbus/dbus-object-tree.c (_dbus_object_tree_list_registered_and_unlock): new function 2003-09-12 Havoc Pennington * glib/dbus-gidl.h: add common base class for all the foo_info types * tools/dbus-viewer.c: add GTK-based introspection UI thingy similar to kdcop * test/Makefile.am: try test srcdir -ef . in addition to test srcdir = ., one of them should work (yeah lame) * glib/Makefile.am: build the "idl" parser stuff as a convenience library * glib/dbus-gparser.h: make description_load routines return NodeInfo* not Parser* * Makefile.am (SUBDIRS): build test dir after all library dirs * configure.in: add GTK+ detection --- dbus/dbus-connection-internal.h | 5 +- dbus/dbus-connection.c | 28 ++++++- dbus/dbus-connection.h | 3 + dbus/dbus-internals.h | 3 +- dbus/dbus-object-tree.c | 164 +++++++++++++++++++++++++++++++++++--- dbus/dbus-object-tree.h | 4 +- dbus/dbus-pending-call.c | 171 +++++++++++++++++++++++++++++++++++----- dbus/dbus-pending-call.h | 11 ++- dbus/dbus-threads.c | 1 + 9 files changed, 352 insertions(+), 38 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 5a04dece..b19ab636 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -30,6 +30,7 @@ #include #include #include +#include DBUS_BEGIN_DECLS; @@ -104,9 +105,9 @@ struct DBusPendingCall { DBusAtomic refcount; /**< reference count */ + DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ + DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ - void *user_data; /**< user data for function */ - DBusFreeFunction free_user_data; /**< free the user data */ DBusConnection *connection; /**< Connections we're associated with */ DBusMessage *reply; /**< Reply (after we've received it) */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index bab6ffd8..b55f270c 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -3101,7 +3101,6 @@ dbus_connection_register_object_path (DBusConnection *connection, * path. You can use this to establish a default message handling * policy for a whole "subdirectory." * - * * @param connection the connection * @param path #NULL-terminated array of path elements * @param vtable the virtual table @@ -3136,6 +3135,7 @@ dbus_connection_register_fallback (DBusConnection *connection, /** * Unregisters the handler registered with exactly the given path. * It's a bug to call this function for a path that isn't registered. + * Can unregister both fallback paths and object paths. * * @param connection the connection * @param path the #NULL-terminated array of path elements @@ -3154,6 +3154,32 @@ dbus_connection_unregister_object_path (DBusConnection *connection, path); } +/** + * Lists the registered fallback handlers and object path handlers at + * the given parent_path. The returned array should be freed with + * dbus_free_string_array(). + * + * @param connection the connection + * @param parent_path the path to list the child handlers of + * @param child_entries returns #NULL-terminated array of children + * @returns #FALSE if no memory to allocate the child entries + */ +dbus_bool_t +dbus_connection_list_registered (DBusConnection *connection, + const char **parent_path, + char ***child_entries) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (parent_path != NULL, FALSE); + _dbus_return_val_if_fail (child_entries != NULL, FALSE); + + CONNECTION_LOCK (connection); + + return _dbus_object_tree_list_registered_and_unlock (connection->objects, + parent_path, + child_entries); +} + static DBusDataSlotAllocator slot_allocator; _DBUS_DEFINE_GLOBAL_LOCK (connection_slots); diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index abc88056..a4212c74 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -240,6 +240,9 @@ dbus_bool_t dbus_connection_register_fallback (DBusConnection void dbus_connection_unregister_object_path (DBusConnection *connection, const char **path); +dbus_bool_t dbus_connection_list_registered (DBusConnection *connection, + const char **parent_path, + char ***child_entries); DBUS_END_DECLS; diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 06a011e3..b3010355 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -230,13 +230,14 @@ extern int _dbus_current_generation; _DBUS_DECLARE_GLOBAL_LOCK (list); _DBUS_DECLARE_GLOBAL_LOCK (connection_slots); +_DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots); _DBUS_DECLARE_GLOBAL_LOCK (server_slots); _DBUS_DECLARE_GLOBAL_LOCK (message_slots); _DBUS_DECLARE_GLOBAL_LOCK (atomic); _DBUS_DECLARE_GLOBAL_LOCK (bus); _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); _DBUS_DECLARE_GLOBAL_LOCK (system_users); -#define _DBUS_N_GLOBAL_LOCKS (8) +#define _DBUS_N_GLOBAL_LOCKS (9) dbus_bool_t _dbus_threads_init_debug (void); diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index 9922dec4..07d3ae59 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -25,6 +25,7 @@ #include "dbus-internals.h" #include "dbus-hash.h" #include "dbus-protocol.h" +#include "dbus-string.h" #include #include @@ -34,13 +35,7 @@ * @brief DBusObjectTree is used by DBusConnection to track the object tree * * 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. + * are all library-internal. * * @{ */ @@ -542,6 +537,101 @@ _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) tree->root = NULL; } +static dbus_bool_t +_dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries) +{ + DBusObjectSubtree *subtree; + char **retval; + + _dbus_assert (parent_path != NULL); + _dbus_assert (child_entries != NULL); + + *child_entries = NULL; + + subtree = find_subtree (tree, parent_path, NULL); + if (subtree == NULL) + { + retval = dbus_new0 (char *, 1); + if (retval == NULL) + goto out; + } + else + { + int i; + retval = dbus_new0 (char*, subtree->n_subtrees + 1); + if (retval == NULL) + goto out; + i = 0; + while (i < subtree->n_subtrees) + { + retval[i] = _dbus_strdup (subtree->subtrees[i]->name); + if (retval[i] == NULL) + { + dbus_free_string_array (retval); + retval = NULL; + goto out; + } + ++i; + } + } + + out: + + *child_entries = retval; + return retval != NULL; +} + +static DBusHandlerResult +handle_default_introspect_unlocked (DBusObjectTree *tree, + DBusMessage *message, + const char **path) +{ + DBusString xml; + DBusHandlerResult result; + char **children; + int i; + + if (!dbus_message_is_method_call (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE, + "Introspect")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!_dbus_string_init (&xml)) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + + children = NULL; + if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children)) + goto out; + + if (!_dbus_string_append (&xml, "\n")) + goto out; + + i = 0; + while (children[i] != NULL) + { + if (!_dbus_string_append_printf (&xml, " \n", + children[i])) + goto out; + + ++i; + } + + if (!_dbus_string_append (&xml, "\n")) + goto out; + + result = DBUS_HANDLER_RESULT_HANDLED; + + out: + _dbus_string_free (&xml); + dbus_free_string_array (children); + + return result; +} + /** * Tries to dispatch a message by directing it to handler for the * object path listed in the message header, if any. Messages are @@ -572,12 +662,23 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, path = NULL; if (!dbus_message_get_path_decomposed (message, &path)) { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); + _dbus_verbose ("No memory to get decomposed path\n"); + return DBUS_HANDLER_RESULT_NEED_MEMORY; } if (path == NULL) { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); + _dbus_verbose ("No path field in message\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -649,30 +750,40 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, 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); + + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + goto free_and_return; } link = next; } + free_and_return: + + if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + { + /* This hardcoded default handler does a minimal Introspect() + */ + result = handle_default_introspect_unlocked (tree, message, + (const char**) path); + } + #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif _dbus_connection_unlock (tree->connection); - - free_and_return: + while (list != NULL) { link = _dbus_list_get_first_link (&list); _dbus_object_subtree_unref (link->data); _dbus_list_remove_link (&list, link); } + dbus_free_string_array (path); return result; @@ -770,6 +881,35 @@ _dbus_object_subtree_unref (DBusObjectSubtree *subtree) } } +/** + * Lists the registered fallback handlers and object path handlers at + * the given parent_path. The returned array should be freed with + * dbus_free_string_array(). + * + * @param connection the connection + * @param parent_path the path to list the child handlers of + * @param child_entries returns #NULL-terminated array of children + * @returns #FALSE if no memory to allocate the child entries + */ +dbus_bool_t +_dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries) +{ + dbus_bool_t result; + + result = _dbus_object_tree_list_registered_unlocked (tree, + parent_path, + child_entries); + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_unlock (tree->connection); + + return result; +} + /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h index 21d8b5f1..bf34d972 100644 --- a/dbus/dbus-object-tree.h +++ b/dbus/dbus-object-tree.h @@ -44,7 +44,9 @@ DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree DBusMessage *message); void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree); - +dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries); DBUS_END_DECLS; #endif /* DBUS_OBJECT_TREE_H */ diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c index 2b6021e9..dad444e3 100644 --- a/dbus/dbus-pending-call.c +++ b/dbus/dbus-pending-call.c @@ -38,6 +38,8 @@ * @{ */ +static dbus_int32_t notify_user_data_slot = -1; + /** * Creates a new pending reply object. * @@ -58,11 +60,17 @@ _dbus_pending_call_new (DBusConnection *connection, if (timeout_milliseconds == -1) timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; + + if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot)) + return NULL; pending = dbus_new (DBusPendingCall, 1); if (pending == NULL) - return NULL; + { + dbus_pending_call_free_data_slot (¬ify_user_data_slot); + return NULL; + } timeout = _dbus_timeout_new (timeout_milliseconds, timeout_handler, @@ -70,6 +78,7 @@ _dbus_pending_call_new (DBusConnection *connection, if (timeout == NULL) { + dbus_pending_call_free_data_slot (¬ify_user_data_slot); dbus_free (pending); return NULL; } @@ -77,6 +86,8 @@ _dbus_pending_call_new (DBusConnection *connection, pending->refcount.value = 1; pending->connection = connection; pending->timeout = timeout; + + _dbus_data_slot_list_init (&pending->slot_list); return pending; } @@ -94,7 +105,13 @@ _dbus_pending_call_notify (DBusPendingCall *pending) pending->completed = TRUE; if (pending->function) - (* pending->function) (pending, pending->user_data); + { + void *user_data; + user_data = dbus_pending_call_get_data (pending, + notify_user_data_slot); + + (* pending->function) (pending, user_data); + } } /** @} */ @@ -154,9 +171,8 @@ dbus_pending_call_unref (DBusPendingCall *pending) _dbus_assert (!pending->timeout_added); /* this assumes we aren't holding connection lock... */ - if (pending->free_user_data) - (* pending->free_user_data) (pending->user_data); - + _dbus_data_slot_list_free (&pending->slot_list); + if (pending->timeout != NULL) _dbus_timeout_unref (pending->timeout); @@ -174,6 +190,8 @@ dbus_pending_call_unref (DBusPendingCall *pending) } dbus_free (pending); + + dbus_pending_call_free_data_slot (¬ify_user_data_slot); } } @@ -185,28 +203,24 @@ dbus_pending_call_unref (DBusPendingCall *pending) * @param function notifier function * @param user_data data to pass to notifier function * @param free_user_data function to free the user data - * + * @returns #FALSE if not enough memory */ -void +dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, void *user_data, DBusFreeFunction free_user_data) { - DBusFreeFunction old_free_func; - void *old_user_data; - - _dbus_return_if_fail (pending != NULL); + _dbus_return_val_if_fail (pending != NULL, FALSE); - old_free_func = pending->free_user_data; - old_user_data = pending->user_data; - - pending->user_data = user_data; - pending->free_user_data = free_user_data; + /* could invoke application code! */ + if (!dbus_pending_call_set_data (pending, notify_user_data_slot, + user_data, free_user_data)) + return FALSE; + pending->function = function; - if (old_free_func) - (* old_free_func) (old_user_data); + return TRUE; } /** @@ -230,9 +244,10 @@ dbus_pending_call_cancel (DBusPendingCall *pending) * Checks whether the pending call has received a reply * yet, or not. * + * @todo not thread safe? I guess it has to lock though it sucks + * * @param pending the pending call - * @returns #TRUE if a reply has been received - */ + * @returns #TRUE if a reply has been received */ dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending) { @@ -245,6 +260,9 @@ dbus_pending_call_get_completed (DBusPendingCall *pending) * have to keep a reference count on the pending call (or add one * to the message). * + * @todo not thread safe? I guess it has to lock though it sucks + * @todo maybe to make this threadsafe, it should be steal_reply(), i.e. only one thread can ever get the message + * * @param pending the pending call * @returns the reply message or #NULL. */ @@ -260,6 +278,9 @@ dbus_pending_call_get_reply (DBusPendingCall *pending) * main loop or process other messages, it simply waits for the reply * in question. * + * If the pending call is already completed, this function returns + * immediately. + * * @todo when you start blocking, the timeout is reset, but it should * really only use time remaining since the pending call was created. * @@ -269,6 +290,9 @@ void dbus_pending_call_block (DBusPendingCall *pending) { DBusMessage *message; + + if (dbus_pending_call_get_completed (pending)) + return; message = _dbus_connection_block_for_reply (pending->connection, pending->reply_serial, @@ -279,6 +303,113 @@ dbus_pending_call_block (DBusPendingCall *pending) dbus_message_unref (message); } +static DBusDataSlotAllocator slot_allocator; +_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots); + +/** + * Allocates an integer ID to be used for storing application-specific + * data on any DBusPendingCall. The allocated ID may then be used + * with dbus_pending_call_set_data() and dbus_pending_call_get_data(). + * The passed-in slot must be initialized to -1, and is filled in + * with the slot ID. If the passed-in slot is not -1, it's assumed + * to be already allocated, and its refcount is incremented. + * + * The allocated slot is global, i.e. all DBusPendingCall objects will + * have a slot with the given integer ID reserved. + * + * @param slot_p address of a global variable storing the slot + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) +{ + return _dbus_data_slot_allocator_alloc (&slot_allocator, + _DBUS_LOCK_NAME (pending_call_slots), + slot_p); +} + +/** + * Deallocates a global ID for #DBusPendingCall data slots. + * dbus_pending_call_get_data() and dbus_pending_call_set_data() may + * no longer be used with this slot. Existing data stored on existing + * DBusPendingCall objects will be freed when the #DBusPendingCall is + * finalized, but may not be retrieved (and may only be replaced if + * someone else reallocates the slot). When the refcount on the + * passed-in slot reaches 0, it is set to -1. + * + * @param slot_p address storing the slot to deallocate + */ +void +dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) +{ + _dbus_return_if_fail (*slot_p >= 0); + + _dbus_data_slot_allocator_free (&slot_allocator, slot_p); +} + +/** + * Stores a pointer on a #DBusPendingCall, along + * with an optional function to be used for freeing + * the data when the data is set again, or when + * the pending call is finalized. The slot number + * must have been allocated with dbus_pending_call_allocate_data_slot(). + * + * @param pending the pending_call + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +dbus_pending_call_set_data (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func) +{ + DBusFreeFunction old_free_func; + void *old_data; + dbus_bool_t retval; + + _dbus_return_val_if_fail (pending != NULL, FALSE); + _dbus_return_val_if_fail (slot >= 0, FALSE); + + retval = _dbus_data_slot_list_set (&slot_allocator, + &pending->slot_list, + slot, data, free_data_func, + &old_free_func, &old_data); + + if (retval) + { + if (old_free_func) + (* old_free_func) (old_data); + } + + return retval; +} + +/** + * Retrieves data previously set with dbus_pending_call_set_data(). + * The slot must still be allocated (must not have been freed). + * + * @param pending the pending_call + * @param slot the slot to get data from + * @returns the data, or #NULL if not found + */ +void* +dbus_pending_call_get_data (DBusPendingCall *pending, + dbus_int32_t slot) +{ + void *res; + + _dbus_return_val_if_fail (pending != NULL, NULL); + + res = _dbus_data_slot_list_get (&slot_allocator, + &pending->slot_list, + slot); + + return res; +} + /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h index 81af872f..4f1e92c0 100644 --- a/dbus/dbus-pending-call.h +++ b/dbus/dbus-pending-call.h @@ -35,7 +35,7 @@ DBUS_BEGIN_DECLS; void dbus_pending_call_ref (DBusPendingCall *pending); void dbus_pending_call_unref (DBusPendingCall *pending); -void dbus_pending_call_set_notify (DBusPendingCall *pending, +dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, void *user_data, DBusFreeFunction free_user_data); @@ -44,6 +44,15 @@ dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pen DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending); void dbus_pending_call_block (DBusPendingCall *pending); +dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p); +void dbus_pending_call_free_data_slot (dbus_int32_t *slot_p); +dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func); +void* dbus_pending_call_get_data (DBusPendingCall *pending, + dbus_int32_t slot); + DBUS_END_DECLS; #endif /* DBUS_PENDING_CALL_H */ diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index c5ce638f..2170c465 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -223,6 +223,7 @@ init_global_locks (void) #define LOCK_ADDR(name) (& _dbus_lock_##name) LOCK_ADDR (list), LOCK_ADDR (connection_slots), + LOCK_ADDR (pending_call_slots), LOCK_ADDR (server_slots), LOCK_ADDR (message_slots), LOCK_ADDR (atomic), -- cgit From daf8d6579e1ae0ea748810b63180bd5eea2ab9c4 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Sun, 21 Sep 2003 18:43:20 +0000 Subject: 2003-09-21 Mark McLoughlin * doc/dbus-specification.sgml: Change the header field name to be an enum and update the rest of the spec to reference the fields using the conventinal name. * dbus/dbus-protocol.h: update to reflect the spec. * doc/TODO: add item to remove the 4 byte alignment requirement. * dbus/dbus-message.c: Remove the code to generalise the header/body length and serial number header fields as named header fields so we can reference field names using the protocol values. (append_int_field), (append_uint_field), (append_string_field): Append the field name as a byte rather than four chars. (delete_int_or_uint_field), (delete_string_field): reflect the fact that the field name and typecode now occupy 4 bytes instead of 8. (decode_string_field), (decode_header_data): update to reflect protocol changes and move the field specific encoding from decode_string_field() back into decode_header_data(). * dbus/dbus-internals.[ch]: (_dbus_header_field_to_string): Add utility to aid debugging. * dbus/dbus-message-builder.c: (append_string_field), (_dbus_message_data_load): Update to reflect protocol changes; Change the FIELD_NAME directive to HEADER_FIELD and allow it to take the field's conventional name rather than the actual value. * test/data/*/*.message: Update to use HEADER_FIELD instead of FIELD_NAME; Always align the header on an 8 byte boundary *before* updating the header length. --- dbus/dbus-internals.c | 32 +++ dbus/dbus-internals.h | 3 +- dbus/dbus-message-builder.c | 46 +++- dbus/dbus-message.c | 525 +++++++++++++++++++------------------------- dbus/dbus-protocol.h | 17 +- 5 files changed, 304 insertions(+), 319 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 463e62e1..cf1cc391 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -389,6 +389,38 @@ _dbus_type_to_string (int type) } } +/** + * Returns a string describing the given name. + * + * @param header_field the field to describe + * @returns a constant string describing the field + */ +const char * +_dbus_header_field_to_string (int header_field) +{ + switch (header_field) + { + case DBUS_HEADER_FIELD_INVALID: + return "invalid"; + case DBUS_HEADER_FIELD_PATH: + return "path"; + case DBUS_HEADER_FIELD_INTERFACE: + return "interface"; + case DBUS_HEADER_FIELD_MEMBER: + return "member"; + case DBUS_HEADER_FIELD_ERROR_NAME: + return "error-name"; + case DBUS_HEADER_FIELD_REPLY_SERIAL: + return "reply-serial"; + case DBUS_HEADER_FIELD_SERVICE: + return "service"; + case DBUS_HEADER_FIELD_SENDER_SERVICE: + return "sender-service"; + default: + return "unknown"; + } +} + #ifndef DBUS_DISABLE_CHECKS /** String used in _dbus_return_if_fail macro */ const char _dbus_return_if_fail_warning_format[] = diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index b3010355..fa1ad19c 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -184,7 +184,8 @@ void _dbus_verbose_bytes_of_string (const DBusString *str, int len); -const char* _dbus_type_to_string (int type); +const char* _dbus_type_to_string (int type); +const char* _dbus_header_field_to_string (int header_field); extern const char _dbus_no_memory_message[]; #define _DBUS_SET_OOM(error) dbus_set_error ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message) diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 52c78227..7e2dff0d 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -294,7 +294,7 @@ message_type_from_string (const DBusString *str, static dbus_bool_t append_string_field (DBusString *dest, int endian, - const char *field_name, + int field, int type, const char *value) { @@ -306,9 +306,9 @@ append_string_field (DBusString *dest, return FALSE; } - if (!_dbus_string_append (dest, field_name)) + if (!_dbus_string_append_byte (dest, field)) { - _dbus_warn ("couldn't append field name\n"); + _dbus_warn ("couldn't append field name byte\n"); return FALSE; } @@ -363,7 +363,7 @@ append_string_field (DBusString *dest, * (or if no START_LENGTH, absolute length) * LENGTH inserts the saved length of the same name * CHOP chops last N bytes off the data - * FIELD_NAME inserts 4-byte field name + * HEADER_FIELD inserts a header field name byte * TYPE inserts a typecode byte * @endcode * @@ -679,14 +679,34 @@ _dbus_message_data_load (DBusString *dest, PERFORM_UNALIGN (dest); } else if (_dbus_string_starts_with_c_str (&line, - "FIELD_NAME")) + "HEADER_FIELD")) { + int field; + _dbus_string_delete_first_word (&line); - if (_dbus_string_get_length (&line) != 4) + if (_dbus_string_starts_with_c_str (&line, "INVALID")) + field = DBUS_HEADER_FIELD_INVALID; + else if (_dbus_string_starts_with_c_str (&line, "PATH")) + field = DBUS_HEADER_FIELD_PATH; + else if (_dbus_string_starts_with_c_str (&line, "INTERFACE")) + field = DBUS_HEADER_FIELD_INTERFACE; + else if (_dbus_string_starts_with_c_str (&line, "MEMBER")) + field = DBUS_HEADER_FIELD_MEMBER; + else if (_dbus_string_starts_with_c_str (&line, "ERROR_NAME")) + field = DBUS_HEADER_FIELD_ERROR_NAME; + else if (_dbus_string_starts_with_c_str (&line, "REPLY_SERIAL")) + field = DBUS_HEADER_FIELD_REPLY_SERIAL; + else if (_dbus_string_starts_with_c_str (&line, "SERVICE")) + field = DBUS_HEADER_FIELD_SERVICE; + else if (_dbus_string_starts_with_c_str (&line, "SENDER_SERVICE")) + field = DBUS_HEADER_FIELD_SENDER_SERVICE; + else if (_dbus_string_starts_with_c_str (&line, "UNKNOWN")) + field = 22; /* random unknown header field */ + else { - _dbus_warn ("Field name must be four characters not \"%s\"\n", - _dbus_string_get_const_data (&line)); + _dbus_warn ("%s is not a valid header field name\n", + _dbus_string_get_const_data (&line)); goto parse_failed; } @@ -694,10 +714,12 @@ _dbus_message_data_load (DBusString *dest, unalign = FALSE; else _dbus_string_align_length (dest, 4); - - if (!_dbus_string_copy (&line, 0, dest, - _dbus_string_get_length (dest))) - goto parse_failed; + + if (!_dbus_string_append_byte (dest, field)) + { + _dbus_warn ("could not append header field name byte\n"); + goto parse_failed; + } } else if (_dbus_string_starts_with_c_str (&line, "TYPE")) diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index d62cbf4f..2ed421d7 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -42,36 +42,6 @@ * @{ */ -enum -{ - FIELD_HEADER_LENGTH, - FIELD_BODY_LENGTH, - FIELD_CLIENT_SERIAL, - FIELD_PATH, - FIELD_INTERFACE, - FIELD_MEMBER, - FIELD_ERROR_NAME, - FIELD_SERVICE, - FIELD_SENDER_SERVICE, - FIELD_REPLY_SERIAL, - - FIELD_LAST -}; - -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_SERVICE */ - TRUE /* FIELD_REPLY_SERIAL */ -}; - /** * Cached information about a header field in the message */ @@ -83,13 +53,20 @@ typedef struct } HeaderField; /** Offset to byte order from start of header */ -#define BYTE_ORDER_OFFSET 0 +#define BYTE_ORDER_OFFSET 0 /** Offset to type from start of header */ -#define TYPE_OFFSET 1 +#define TYPE_OFFSET 1 /** Offset to flags from start of header */ -#define FLAGS_OFFSET 2 +#define FLAGS_OFFSET 2 /** Offset to version from start of header */ -#define VERSION_OFFSET 3 +#define VERSION_OFFSET 3 +/** Offset to header length from start of header */ +#define HEADER_LENGTH_OFFSET 4 +/** Offset to body length from start of header */ +#define BODY_LENGTH_OFFSET 8 +/** Offset to client serial from start of header */ +#define CLIENT_SERIAL_OFFSET 12 + /** * @brief Internals of DBusMessage @@ -107,9 +84,9 @@ struct DBusMessage * independently realloc it. */ - HeaderField header_fields[FIELD_LAST]; /**< Track the location - * of each field in "header" - */ + HeaderField header_fields[DBUS_HEADER_FIELD_LAST + 1]; /**< Track the location + * of each field in "header" + */ dbus_uint32_t client_serial; /**< Cached client serial value for speed */ dbus_uint32_t reply_serial; /**< Cached reply serial value for speed */ @@ -217,7 +194,7 @@ adjust_field_offsets (DBusMessage *message, return; i = 0; - while (i < FIELD_LAST) + while (i <= DBUS_HEADER_FIELD_LAST) { if (message->header_fields[i].offset > offsets_after) message->header_fields[i].offset += delta; @@ -234,7 +211,7 @@ get_int_field (DBusMessage *message, { int offset; - _dbus_assert (field < FIELD_LAST); + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); offset = message->header_fields[field].offset; @@ -254,7 +231,7 @@ get_uint_field (DBusMessage *message, { int offset; - _dbus_assert (field < FIELD_LAST); + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); offset = message->header_fields[field].offset; @@ -277,7 +254,7 @@ get_string_field (DBusMessage *message, offset = message->header_fields[field].offset; - _dbus_assert (field < FIELD_LAST); + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); if (offset < 0) return NULL; @@ -308,7 +285,7 @@ get_path_field_decomposed (DBusMessage *message, offset = message->header_fields[field].offset; - _dbus_assert (field < FIELD_LAST); + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); if (offset < 0) { @@ -327,7 +304,6 @@ get_path_field_decomposed (DBusMessage *message, static dbus_bool_t append_int_field (DBusMessage *message, int field, - const char *name, int value) { int orig_len; @@ -341,7 +317,7 @@ append_int_field (DBusMessage *message, if (!_dbus_string_align_length (&message->header, 4)) goto failed; - if (!_dbus_string_append_len (&message->header, name, 4)) + if (!_dbus_string_append_byte (&message->header, field)) goto failed; if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32)) @@ -378,8 +354,7 @@ append_int_field (DBusMessage *message, static dbus_bool_t append_uint_field (DBusMessage *message, int field, - const char *name, - int value) + int value) { int orig_len; @@ -392,7 +367,7 @@ append_uint_field (DBusMessage *message, if (!_dbus_string_align_length (&message->header, 4)) goto failed; - if (!_dbus_string_append_len (&message->header, name, 4)) + if (!_dbus_string_append_byte (&message->header, field)) goto failed; if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_UINT32)) @@ -429,7 +404,6 @@ static dbus_bool_t append_string_field (DBusMessage *message, int field, int type, - const char *name, const char *value) { int orig_len; @@ -443,7 +417,7 @@ append_string_field (DBusMessage *message, if (!_dbus_string_align_length (&message->header, 4)) goto failed; - if (!_dbus_string_append_len (&message->header, name, 4)) + if (!_dbus_string_append_byte (&message->header, field)) goto failed; if (!_dbus_string_append_byte (&message->header, type)) @@ -488,23 +462,22 @@ delete_int_or_uint_field (DBusMessage *message, int offset = message->header_fields[field].offset; _dbus_assert (!message->locked); - _dbus_assert (field_is_named[field]); if (offset < 0) return; clear_header_padding (message); - /* The field typecode and name take up 8 bytes */ + /* The field typecode and name take up 4 bytes */ _dbus_string_delete (&message->header, - offset - 8, - 12); + offset - 4, + 8); message->header_fields[field].offset = -1; adjust_field_offsets (message, - offset - 8, - - 12); + offset - 4, + - 8); append_header_padding (message); } @@ -519,7 +492,6 @@ delete_string_field (DBusMessage *message, int delete_len; _dbus_assert (!message->locked); - _dbus_assert (field_is_named[field]); if (offset < 0) return; @@ -528,19 +500,19 @@ delete_string_field (DBusMessage *message, get_string_field (message, field, &len); - /* The field typecode and name take up 8 bytes, and the nul + /* The field typecode and name take up 4 bytes, and the nul * termination is 1 bytes, string length integer is 4 bytes */ - delete_len = 8 + 4 + 1 + len; + delete_len = 4 + 4 + 1 + len; _dbus_string_delete (&message->header, - offset - 8, + offset - 4, delete_len); message->header_fields[field].offset = -1; adjust_field_offsets (message, - offset - 8, + offset - 4, - delete_len); append_header_padding (message); @@ -593,10 +565,9 @@ set_uint_field (DBusMessage *message, switch (field) { - case FIELD_REPLY_SERIAL: - return append_uint_field (message, field, - DBUS_HEADER_FIELD_REPLY, - value); + case DBUS_HEADER_FIELD_REPLY_SERIAL: + return append_uint_field (message, field, value); + default: _dbus_assert_not_reached ("appending a uint field we don't support appending"); return FALSE; @@ -629,30 +600,14 @@ set_string_field (DBusMessage *message, switch (field) { - 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, type, - DBUS_HEADER_FIELD_INTERFACE, - value); - case FIELD_MEMBER: - return append_string_field (message, field, type, - DBUS_HEADER_FIELD_MEMBER, - value); - case FIELD_ERROR_NAME: - return append_string_field (message, field, type, - DBUS_HEADER_FIELD_ERROR_NAME, - value); - case FIELD_SERVICE: - return append_string_field (message, field, type, - DBUS_HEADER_FIELD_SERVICE, - value); + case DBUS_HEADER_FIELD_PATH: + case DBUS_HEADER_FIELD_SENDER_SERVICE: + case DBUS_HEADER_FIELD_INTERFACE: + case DBUS_HEADER_FIELD_MEMBER: + case DBUS_HEADER_FIELD_ERROR_NAME: + case DBUS_HEADER_FIELD_SERVICE: + return append_string_field (message, field, type, value); + default: _dbus_assert_not_reached ("appending a string field we don't support appending"); return FALSE; @@ -714,9 +669,12 @@ _dbus_message_set_serial (DBusMessage *message, { _dbus_assert (!message->locked); _dbus_assert (dbus_message_get_serial (message) == 0); - - set_uint_field (message, FIELD_CLIENT_SERIAL, - serial); + + _dbus_marshal_set_uint32 (&message->header, + message->byte_order, + CLIENT_SERIAL_OFFSET, + serial); + message->client_serial = serial; } @@ -734,7 +692,8 @@ dbus_message_set_reply_serial (DBusMessage *message, { _dbus_assert (!message->locked); - if (set_uint_field (message, FIELD_REPLY_SERIAL, + if (set_uint_field (message, + DBUS_HEADER_FIELD_REPLY_SERIAL, reply_serial)) { message->reply_serial = reply_serial; @@ -894,15 +853,12 @@ dbus_message_create_header (DBusMessage *message, if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION)) return FALSE; - message->header_fields[FIELD_HEADER_LENGTH].offset = 4; if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0)) return FALSE; - message->header_fields[FIELD_BODY_LENGTH].offset = 8; if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0)) return FALSE; - message->header_fields[FIELD_CLIENT_SERIAL].offset = 12; if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1)) return FALSE; @@ -911,8 +867,8 @@ dbus_message_create_header (DBusMessage *message, if (path != NULL) { if (!append_string_field (message, - FIELD_PATH, DBUS_TYPE_OBJECT_PATH, DBUS_HEADER_FIELD_PATH, + DBUS_TYPE_OBJECT_PATH, path)) return FALSE; } @@ -920,8 +876,8 @@ dbus_message_create_header (DBusMessage *message, if (service != NULL) { if (!append_string_field (message, - FIELD_SERVICE, DBUS_TYPE_STRING, DBUS_HEADER_FIELD_SERVICE, + DBUS_TYPE_STRING, service)) return FALSE; } @@ -929,8 +885,8 @@ dbus_message_create_header (DBusMessage *message, if (interface != NULL) { if (!append_string_field (message, - FIELD_INTERFACE, DBUS_TYPE_STRING, DBUS_HEADER_FIELD_INTERFACE, + DBUS_TYPE_STRING, interface)) return FALSE; } @@ -938,8 +894,8 @@ dbus_message_create_header (DBusMessage *message, if (member != NULL) { if (!append_string_field (message, - FIELD_MEMBER, DBUS_TYPE_STRING, DBUS_HEADER_FIELD_MEMBER, + DBUS_TYPE_STRING, member)) return FALSE; } @@ -947,8 +903,8 @@ dbus_message_create_header (DBusMessage *message, if (error_name != NULL) { if (!append_string_field (message, - FIELD_ERROR_NAME, DBUS_TYPE_STRING, DBUS_HEADER_FIELD_ERROR_NAME, + DBUS_TYPE_STRING, error_name)) return FALSE; } @@ -971,13 +927,15 @@ _dbus_message_lock (DBusMessage *message) if (!message->locked) { /* Fill in our lengths */ - set_uint_field (message, - FIELD_HEADER_LENGTH, - _dbus_string_get_length (&message->header)); + _dbus_marshal_set_uint32 (&message->header, + message->byte_order, + HEADER_LENGTH_OFFSET, + _dbus_string_get_length (&message->header)); - set_uint_field (message, - FIELD_BODY_LENGTH, - _dbus_string_get_length (&message->body)); + _dbus_marshal_set_uint32 (&message->header, + message->byte_order, + BODY_LENGTH_OFFSET, + _dbus_string_get_length (&message->body)); message->locked = TRUE; } @@ -1023,7 +981,7 @@ dbus_message_new_empty_header (void) _dbus_data_slot_list_init (&message->slot_list); i = 0; - while (i < FIELD_LAST) + while (i <= DBUS_HEADER_FIELD_LAST) { message->header_fields[i].offset = -1; ++i; @@ -1136,7 +1094,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_SERVICE, NULL); + DBUS_HEADER_FIELD_SENDER_SERVICE, + NULL); /* sender is allowed to be null here in peer-to-peer case */ @@ -1222,7 +1181,8 @@ dbus_message_new_error (DBusMessage *reply_to, _dbus_return_val_if_fail (error_name != NULL, NULL); sender = get_string_field (reply_to, - FIELD_SENDER_SERVICE, NULL); + DBUS_HEADER_FIELD_SENDER_SERVICE, + NULL); /* sender may be NULL for non-message-bus case or * when the message bus is dealing with an unregistered @@ -1319,7 +1279,7 @@ dbus_message_copy (const DBusMessage *message) return NULL; } - for (i = 0; i < FIELD_LAST; i++) + for (i = 0; i <= DBUS_HEADER_FIELD_LAST; i++) { retval->header_fields[i].offset = message->header_fields[i].offset; } @@ -1430,13 +1390,13 @@ dbus_message_set_path (DBusMessage *message, if (object_path == NULL) { - delete_string_field (message, FIELD_PATH); + delete_string_field (message, DBUS_HEADER_FIELD_PATH); return TRUE; } else { return set_string_field (message, - FIELD_PATH, + DBUS_HEADER_FIELD_PATH, DBUS_TYPE_OBJECT_PATH, object_path); } @@ -1455,7 +1415,7 @@ dbus_message_get_path (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, NULL); - return get_string_field (message, FIELD_PATH, NULL); + return get_string_field (message, DBUS_HEADER_FIELD_PATH, NULL); } /** @@ -1480,7 +1440,8 @@ dbus_message_get_path_decomposed (DBusMessage *message, _dbus_return_val_if_fail (message != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); - return get_path_field_decomposed (message, FIELD_PATH, + return get_path_field_decomposed (message, + DBUS_HEADER_FIELD_PATH, path); } @@ -1503,13 +1464,13 @@ dbus_message_set_interface (DBusMessage *message, if (interface == NULL) { - delete_string_field (message, FIELD_INTERFACE); + delete_string_field (message, DBUS_HEADER_FIELD_INTERFACE); return TRUE; } else { return set_string_field (message, - FIELD_INTERFACE, + DBUS_HEADER_FIELD_INTERFACE, DBUS_TYPE_STRING, interface); } @@ -1529,7 +1490,7 @@ dbus_message_get_interface (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, NULL); - return get_string_field (message, FIELD_INTERFACE, NULL); + return get_string_field (message, DBUS_HEADER_FIELD_INTERFACE, NULL); } /** @@ -1551,13 +1512,13 @@ dbus_message_set_member (DBusMessage *message, if (member == NULL) { - delete_string_field (message, FIELD_MEMBER); + delete_string_field (message, DBUS_HEADER_FIELD_MEMBER); return TRUE; } else { return set_string_field (message, - FIELD_MEMBER, + DBUS_HEADER_FIELD_MEMBER, DBUS_TYPE_STRING, member); } @@ -1576,7 +1537,9 @@ dbus_message_get_member (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, NULL); - return get_string_field (message, FIELD_MEMBER, NULL); + return get_string_field (message, + DBUS_HEADER_FIELD_MEMBER, + NULL); } /** @@ -1596,13 +1559,14 @@ dbus_message_set_error_name (DBusMessage *message, if (error_name == NULL) { - delete_string_field (message, FIELD_ERROR_NAME); + delete_string_field (message, + DBUS_HEADER_FIELD_ERROR_NAME); return TRUE; } else { return set_string_field (message, - FIELD_ERROR_NAME, + DBUS_HEADER_FIELD_ERROR_NAME, DBUS_TYPE_STRING, error_name); } @@ -1619,7 +1583,9 @@ dbus_message_get_error_name (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, NULL); - return get_string_field (message, FIELD_ERROR_NAME, NULL); + return get_string_field (message, + DBUS_HEADER_FIELD_ERROR_NAME, + NULL); } /** @@ -1638,13 +1604,13 @@ dbus_message_set_destination (DBusMessage *message, if (destination == NULL) { - delete_string_field (message, FIELD_SERVICE); + delete_string_field (message, DBUS_HEADER_FIELD_SERVICE); return TRUE; } else { return set_string_field (message, - FIELD_SERVICE, + DBUS_HEADER_FIELD_SERVICE, DBUS_TYPE_STRING, destination); } @@ -1661,7 +1627,9 @@ dbus_message_get_destination (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, NULL); - return get_string_field (message, FIELD_SERVICE, NULL); + return get_string_field (message, + DBUS_HEADER_FIELD_SERVICE, + NULL); } /** @@ -4113,13 +4081,14 @@ dbus_message_set_sender (DBusMessage *message, if (sender == NULL) { - delete_string_field (message, FIELD_SENDER_SERVICE); + delete_string_field (message, + DBUS_HEADER_FIELD_SENDER_SERVICE); return TRUE; } else { return set_string_field (message, - FIELD_SENDER_SERVICE, + DBUS_HEADER_FIELD_SENDER_SERVICE, DBUS_TYPE_STRING, sender); } @@ -4183,7 +4152,9 @@ dbus_message_get_sender (DBusMessage *message) { _dbus_return_val_if_fail (message != NULL, NULL); - return get_string_field (message, FIELD_SENDER_SERVICE, NULL); + return get_string_field (message, + DBUS_HEADER_FIELD_SENDER_SERVICE, + NULL); } static dbus_bool_t @@ -4566,63 +4537,31 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader, */ #define DBUS_MINIMUM_HEADER_SIZE 16 -/** Pack four characters as in "abcd" into a uint32 */ -#define FOUR_CHARS_TO_UINT32(a, b, c, d) \ - ((((dbus_uint32_t)a) << 24) | \ - (((dbus_uint32_t)b) << 16) | \ - (((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') - -/** 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 \ - FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c') - -/** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */ -#define DBUS_HEADER_FIELD_REPLY_AS_UINT32 \ - FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y') - -/** 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, - HeaderField fields[FIELD_LAST], + int field, + HeaderField *header_field, + DBusString *field_data, int pos, - int type, - int field, - const char *field_name) + int type) { - DBusString tmp; int string_data_pos; + + _dbus_assert (header_field != NULL); + _dbus_assert (field_data != NULL); - if (fields[field].offset >= 0) + if (header_field->offset >= 0) { _dbus_verbose ("%s field provided twice\n", - field_name); + _dbus_header_field_to_string (field)); return FALSE; } if (type != DBUS_TYPE_STRING) { _dbus_verbose ("%s field has wrong type %s\n", - field_name, _dbus_type_to_string (type)); + _dbus_header_field_to_string (field), + _dbus_type_to_string (type)); return FALSE; } @@ -4633,63 +4572,15 @@ decode_string_field (const DBusString *data, string_data_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4; _dbus_assert (string_data_pos < _dbus_string_get_length (data)); - _dbus_string_init_const (&tmp, + _dbus_string_init_const (field_data, _dbus_string_get_const_data (data) + string_data_pos); - if (field == FIELD_INTERFACE) - { - 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_equal_c_str (&tmp, - DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL)) - { - _dbus_verbose ("Message is on the local interface\n"); - return FALSE; - } - } - 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 || - field == FIELD_SENDER_SERVICE) - { - if (!_dbus_string_validate_service (&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 - { - _dbus_assert_not_reached ("Unknown field\n"); - } - - fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4); + header_field->offset = _DBUS_ALIGN_VALUE (pos, 4); #if 0 - _dbus_verbose ("Found field %s name at offset %d\n", - field_name, fields[field].offset); + _dbus_verbose ("Found field %s at offset %d\n", + _dbus_header_field_to_string (field), + header_field->offset); #endif return TRUE; @@ -4700,12 +4591,13 @@ decode_header_data (const DBusString *data, int header_len, int byte_order, int message_type, - HeaderField fields[FIELD_LAST], + HeaderField fields[DBUS_HEADER_FIELD_LAST + 1], int *message_padding) { - const char *field; + DBusString field_data; int pos, new_pos; int i; + int field; int type; if (header_len < 16) @@ -4715,38 +4607,32 @@ decode_header_data (const DBusString *data, } i = 0; - while (i < FIELD_LAST) + while (i <= DBUS_HEADER_FIELD_LAST) { fields[i].offset = -1; ++i; } - fields[FIELD_HEADER_LENGTH].offset = 4; - fields[FIELD_BODY_LENGTH].offset = 8; - fields[FIELD_CLIENT_SERIAL].offset = 12; - - /* Now handle the named fields. A real named field is at least 4 - * bytes for the name, plus a type code (1 byte) plus padding. So - * if we have less than 8 bytes left, it must be alignment padding, - * not a field. While >= 8 bytes can't be entirely alignment - * padding. + /* Now handle the named fields. A real named field is at least 1 + * byte for the name, plus a type code (1 byte) plus padding, plus + * the field value. So if we have less than 8 bytes left, it must + * be alignment padding, not a field. While >= 8 bytes can't be + * entirely alignment padding. */ pos = 16; while ((pos + 7) < header_len) { pos = _DBUS_ALIGN_VALUE (pos, 4); - if ((pos + 4) > header_len) + if ((pos + 1) > header_len) { _dbus_verbose ("not enough space remains in header for header field value\n"); return FALSE; } - field = _dbus_string_get_const_data_len (data, pos, 4); - pos += 4; + field = _dbus_string_get_byte (data, pos); + pos += 1; - _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field); - if (!_dbus_marshal_validate_type (data, pos, &type, &pos)) { _dbus_verbose ("Failed to validate type of named header field\n"); @@ -4765,71 +4651,112 @@ decode_header_data (const DBusString *data, return FALSE; } - switch (DBUS_UINT32_FROM_BE (*(int*)field)) + switch (field) { - case DBUS_HEADER_FIELD_SERVICE_AS_UINT32: - if (!decode_string_field (data, fields, pos, type, - FIELD_SERVICE, - DBUS_HEADER_FIELD_SERVICE)) + case DBUS_HEADER_FIELD_SERVICE: + if (!decode_string_field (data, field, &fields[field], + &field_data, pos, type)) return FALSE; + + if (!_dbus_string_validate_service (&field_data, 0, + _dbus_string_get_length (&field_data))) + { + _dbus_verbose ("service field has invalid content \"%s\"\n", + _dbus_string_get_const_data (&field_data)); + return FALSE; + } break; - case DBUS_HEADER_FIELD_INTERFACE_AS_UINT32: - if (!decode_string_field (data, fields, pos, type, - FIELD_INTERFACE, - DBUS_HEADER_FIELD_INTERFACE)) + case DBUS_HEADER_FIELD_INTERFACE: + if (!decode_string_field (data, field, &fields[field], + &field_data, pos, type)) return FALSE; + + if (!_dbus_string_validate_interface (&field_data, 0, + _dbus_string_get_length (&field_data))) + { + _dbus_verbose ("interface field has invalid content \"%s\"\n", + _dbus_string_get_const_data (&field_data)); + return FALSE; + } + + if (_dbus_string_equal_c_str (&field_data, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL)) + { + _dbus_verbose ("Message is on the local interface\n"); + return FALSE; + } break; - case DBUS_HEADER_FIELD_MEMBER_AS_UINT32: - if (!decode_string_field (data, fields, pos, type, - FIELD_MEMBER, - DBUS_HEADER_FIELD_MEMBER)) + case DBUS_HEADER_FIELD_MEMBER: + if (!decode_string_field (data, field, &fields[field], + &field_data, pos, type)) return FALSE; + + if (!_dbus_string_validate_member (&field_data, 0, + _dbus_string_get_length (&field_data))) + { + _dbus_verbose ("member field has invalid content \"%s\"\n", + _dbus_string_get_const_data (&field_data)); + 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)) + case DBUS_HEADER_FIELD_ERROR_NAME: + if (!decode_string_field (data, field, &fields[field], + &field_data, pos, type)) return FALSE; + + if (!_dbus_string_validate_error_name (&field_data, 0, + _dbus_string_get_length (&field_data))) + { + _dbus_verbose ("error-name field has invalid content \"%s\"\n", + _dbus_string_get_const_data (&field_data)); + return FALSE; + } break; - case DBUS_HEADER_FIELD_SENDER_SERVICE_AS_UINT32: - if (!decode_string_field (data, fields, pos, type, - FIELD_SENDER_SERVICE, - DBUS_HEADER_FIELD_SENDER_SERVICE)) + case DBUS_HEADER_FIELD_SENDER_SERVICE: + if (!decode_string_field (data, field, &fields[field], + &field_data, pos, type)) return FALSE; + + if (!_dbus_string_validate_service (&field_data, 0, + _dbus_string_get_length (&field_data))) + { + _dbus_verbose ("sender-service field has invalid content \"%s\"\n", + _dbus_string_get_const_data (&field_data)); + return FALSE; + } break; - case DBUS_HEADER_FIELD_PATH_AS_UINT32: + case DBUS_HEADER_FIELD_PATH: /* Path was already validated as part of standard * type validation, since there's an OBJECT_PATH * type. */ - if (fields[FIELD_PATH].offset >= 0) + if (fields[field].offset >= 0) { - _dbus_verbose ("%s field provided twice\n", - DBUS_HEADER_FIELD_PATH); + _dbus_verbose ("path field provided twice\n"); return FALSE; } if (type != DBUS_TYPE_OBJECT_PATH) { - _dbus_verbose ("%s field has wrong type\n", DBUS_HEADER_FIELD_PATH); + _dbus_verbose ("path field has wrong type\n"); return FALSE; } - fields[FIELD_PATH].offset = _DBUS_ALIGN_VALUE (pos, 4); + fields[field].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, + fields[field].offset, _dbus_string_get_length (data) - - fields[FIELD_PATH].offset); + fields[field].offset); if (strcmp (s, DBUS_PATH_ORG_FREEDESKTOP_LOCAL) == 0) { _dbus_verbose ("Message is on the local path\n"); @@ -4838,31 +4765,30 @@ decode_header_data (const DBusString *data, } _dbus_verbose ("Found path at offset %d\n", - fields[FIELD_PATH].offset); + fields[field].offset); break; - case DBUS_HEADER_FIELD_REPLY_AS_UINT32: - if (fields[FIELD_REPLY_SERIAL].offset >= 0) + case DBUS_HEADER_FIELD_REPLY_SERIAL: + if (fields[field].offset >= 0) { - _dbus_verbose ("%s field provided twice\n", - DBUS_HEADER_FIELD_REPLY); + _dbus_verbose ("reply field provided twice\n"); return FALSE; } if (type != DBUS_TYPE_UINT32) { - _dbus_verbose ("%s field has wrong type\n", DBUS_HEADER_FIELD_REPLY); + _dbus_verbose ("reply field has wrong type\n"); return FALSE; } - fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos, 4); + fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4); _dbus_verbose ("Found reply serial at offset %d\n", - fields[FIELD_REPLY_SERIAL].offset); + fields[field].offset); break; default: - _dbus_verbose ("Ignoring an unknown header field: %.4s at offset %d\n", + _dbus_verbose ("Ignoring an unknown header field: %d at offset %d\n", field, pos); } @@ -4887,31 +4813,27 @@ decode_header_data (const DBusString *data, { case DBUS_MESSAGE_TYPE_SIGNAL: case DBUS_MESSAGE_TYPE_METHOD_CALL: - if (fields[FIELD_PATH].offset < 0) + if (fields[DBUS_HEADER_FIELD_PATH].offset < 0) { - _dbus_verbose ("No %s field provided\n", - DBUS_HEADER_FIELD_PATH); + _dbus_verbose ("No path field provided\n"); return FALSE; } /* FIXME make this optional, at least for method calls */ - if (fields[FIELD_INTERFACE].offset < 0) + if (fields[DBUS_HEADER_FIELD_INTERFACE].offset < 0) { - _dbus_verbose ("No %s field provided\n", - DBUS_HEADER_FIELD_INTERFACE); + _dbus_verbose ("No interface field provided\n"); return FALSE; } - if (fields[FIELD_MEMBER].offset < 0) + if (fields[DBUS_HEADER_FIELD_MEMBER].offset < 0) { - _dbus_verbose ("No %s field provided\n", - DBUS_HEADER_FIELD_MEMBER); + _dbus_verbose ("No member field provided\n"); return FALSE; } break; case DBUS_MESSAGE_TYPE_ERROR: - if (fields[FIELD_ERROR_NAME].offset < 0) + if (fields[DBUS_HEADER_FIELD_ERROR_NAME].offset < 0) { - _dbus_verbose ("No %s field provided\n", - DBUS_HEADER_FIELD_ERROR_NAME); + _dbus_verbose ("No error-name field provided\n"); return FALSE; } break; @@ -5056,7 +4978,7 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) if (_dbus_string_get_length (&loader->data) >= (header_len + body_len)) { - HeaderField fields[FIELD_LAST]; + HeaderField fields[DBUS_HEADER_FIELD_LAST + 1]; int i; int next_arg; @@ -5123,7 +5045,7 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) /* Copy in the offsets we found */ i = 0; - while (i < FIELD_LAST) + while (i <= DBUS_HEADER_FIELD_LAST) { message->header_fields[i] = fields[i]; ++i; @@ -5173,9 +5095,12 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) * earlier) */ message->reply_serial = get_uint_field (message, - FIELD_REPLY_SERIAL); - message->client_serial = get_uint_field (message, - FIELD_CLIENT_SERIAL); + DBUS_HEADER_FIELD_REPLY_SERIAL); + + message->client_serial = _dbus_demarshal_uint32 (&message->header, + message->byte_order, + CLIENT_SERIAL_OFFSET, + NULL); _dbus_verbose ("Loaded message %p\n", message); } @@ -5751,8 +5676,10 @@ check_message_handling (DBusMessage *message) client_serial = dbus_message_get_serial (message); /* can't use set_serial due to the assertions at the start of it */ - set_uint_field (message, FIELD_CLIENT_SERIAL, - client_serial); + _dbus_marshal_set_uint32 (&message->header, + message->byte_order, + CLIENT_SERIAL_OFFSET, + client_serial); if (client_serial != dbus_message_get_serial (message)) { diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 473a1051..329609dc 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -71,14 +71,17 @@ extern "C" { #define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1 /* Header fields */ -#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" +#define DBUS_HEADER_FIELD_INVALID 0 +#define DBUS_HEADER_FIELD_PATH 1 +#define DBUS_HEADER_FIELD_INTERFACE 2 +#define DBUS_HEADER_FIELD_MEMBER 3 +#define DBUS_HEADER_FIELD_ERROR_NAME 4 +#define DBUS_HEADER_FIELD_REPLY_SERIAL 5 +#define DBUS_HEADER_FIELD_SERVICE 6 +#define DBUS_HEADER_FIELD_SENDER_SERVICE 7 +#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_SENDER_SERVICE + /* Services */ #define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus" #define DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST "org.freedesktop.Broadcast" -- cgit From a683a80c409cc4f2e57ba6a3e60d52f91b8657d0 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 21 Sep 2003 19:53:56 +0000 Subject: 2003-09-21 Havoc Pennington Get matching rules mostly working in the bus; only actually parsing the rule text remains. However, the client side of "signal connections" hasn't been started, this patch is only the bus side. * dbus/dispatch.c: fix for the matching rules changes * bus/driver.c (bus_driver_handle_remove_match) (bus_driver_handle_add_match): send an ack reply from these method calls * glib/dbus-gproxy.c (dbus_gproxy_begin_call): fix order of arguments, reported by Seth Nickell * bus/config-parser.c (append_rule_from_element): support eavesdrop=true|false attribute on policies so match rules can be prevented from snooping on the system bus. * bus/dbus-daemon-1.1.in: consistently use terminology "sender" and "destination" in attribute names; fix some docs bugs; add eavesdrop=true|false attribute * bus/driver.c (bus_driver_handle_add_match) (bus_driver_handle_remove_match): handle AddMatch, RemoveMatch messages * dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST): get rid of broadcast service concept, signals are just always broadcast * bus/signals.c, bus/dispatch.c, bus/connection.c, bus/bus.c: mostly implement matching rules stuff (currently only exposed as signal connections) --- dbus/dbus-errors.h | 13 +++++++------ dbus/dbus-mainloop.c | 2 +- dbus/dbus-protocol.h | 1 - dbus/dbus-transport.c | 2 ++ 4 files changed, 10 insertions(+), 8 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h index ad4801c9..f229188a 100644 --- a/dbus/dbus-errors.h +++ b/dbus/dbus-errors.h @@ -53,13 +53,8 @@ struct DBusError }; #define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed" -#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Activate.ServiceNotFound" -#define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed" -#define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed" -#define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited" -#define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled" -#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed" #define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory" +#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Error.ServiceNotFound" #define DBUS_ERROR_SERVICE_DOES_NOT_EXIST "org.freedesktop.DBus.Error.ServiceDoesNotExist" #define DBUS_ERROR_NO_REPLY "org.freedesktop.DBus.Error.NoReply" #define DBUS_ERROR_IO_ERROR "org.freedesktop.DBus.Error.IOError" @@ -77,6 +72,12 @@ struct DBusError #define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound" #define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod" #define DBUS_ERROR_TIMED_OUT "org.freedesktop.DBus.Error.TimedOut" +#define DBUS_ERROR_MATCH_RULE_NOT_FOUND "org.freedesktop.DBus.Error.MatchRuleNotFound" +#define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed" +#define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed" +#define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited" +#define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled" +#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed" void dbus_error_init (DBusError *error); void dbus_error_free (DBusError *error); diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c index f3b68272..6da5318c 100644 --- a/dbus/dbus-mainloop.c +++ b/dbus/dbus-mainloop.c @@ -28,7 +28,7 @@ #include #include -#define MAINLOOP_SPEW 1 +#define MAINLOOP_SPEW 0 struct DBusLoop { diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 329609dc..a0cf54ef 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -84,7 +84,6 @@ extern "C" { /* 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" diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index 59ec6ea1..4625cf25 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -813,7 +813,9 @@ _dbus_transport_queue_messages (DBusTransport *transport) { DBusDispatchStatus status; +#if 0 _dbus_verbose ("_dbus_transport_queue_messages()\n"); +#endif /* Queue any messages */ while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS) -- cgit From 25cb861980003f81eade8707bfa1a61c9ece1779 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 22 Sep 2003 01:29:14 +0000 Subject: 2003-09-21 Havoc Pennington * dbus/dbus-bus.c (dbus_bus_get): set exit_on_disconnect to TRUE by default for message bus connections. * dbus/dbus-connection.c (dbus_connection_dispatch): exit if exit_on_disconnect flag is set and we process the disconnected signal. (dbus_connection_set_exit_on_disconnect): new function --- dbus/dbus-bus.c | 6 ++++++ dbus/dbus-connection.c | 38 ++++++++++++++++++++++++++++++++++++++ dbus/dbus-connection.h | 4 +++- 3 files changed, 47 insertions(+), 1 deletion(-) (limited to 'dbus') diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index a38b4a26..6d7cb82c 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -338,6 +338,12 @@ dbus_bus_get (DBusBusType type, _DBUS_UNLOCK (bus); return NULL; } + + /* By default we're bound to the lifecycle of + * the message bus. + */ + dbus_connection_set_exit_on_disconnect (connection, + TRUE); if (!dbus_bus_register (connection, error)) { diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index b55f270c..ed7d57d0 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -206,6 +206,8 @@ struct DBusConnection * for the global linked list mempool lock */ DBusObjectTree *objects; /**< Object path handlers registered with this connection */ + + unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */ }; static void _dbus_connection_remove_timeout_locked (DBusConnection *connection, @@ -906,6 +908,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) connection->filter_list = NULL; connection->last_dispatch_status = DBUS_DISPATCH_COMPLETE; /* so we're notified first time there's data */ connection->objects = objects; + connection->exit_on_disconnect = FALSE; _dbus_data_slot_list_init (&connection->slot_list); @@ -1356,6 +1359,30 @@ dbus_connection_get_is_authenticated (DBusConnection *connection) return res; } +/** + * Set whether _exit() should be called when the connection receives a + * disconnect signal. The call to _exit() comes after any handlers for + * the disconnect signal run; handlers can cancel the exit by calling + * this function. + * + * By default, exit_on_disconnect is #FALSE; but for message bus + * connections returned from dbus_bus_get() it will be toggled on + * by default. + * + * @param connection the connection + * @param exit_on_disconnect #TRUE if _exit() should be called after a disconnect signal + */ +void +dbus_connection_set_exit_on_disconnect (DBusConnection *connection, + dbus_bool_t exit_on_disconnect) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + connection->exit_on_disconnect = exit_on_disconnect != FALSE; + CONNECTION_UNLOCK (connection); +} + static DBusPreallocatedSend* _dbus_connection_preallocate_send_unlocked (DBusConnection *connection) { @@ -2616,6 +2643,17 @@ dbus_connection_dispatch (DBusConnection *connection) } else { + if (connection->exit_on_disconnect && + dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) + { + _dbus_verbose ("Exiting on Disconnected signal\n"); + CONNECTION_UNLOCK (connection); + _dbus_exit (1); + _dbus_assert_not_reached ("Call to exit() returned"); + } + _dbus_list_free_link (message_link); dbus_message_unref (message); /* don't want the message to count in max message limits * in computing dispatch status below diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index a4212c74..aa92b30a 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -100,6 +100,8 @@ void dbus_connection_unref (DBusConnection void dbus_connection_disconnect (DBusConnection *connection); dbus_bool_t dbus_connection_get_is_connected (DBusConnection *connection); dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection *connection); +void dbus_connection_set_exit_on_disconnect (DBusConnection *connection, + dbus_bool_t exit_on_disconnect); void dbus_connection_flush (DBusConnection *connection); DBusMessage* dbus_connection_borrow_message (DBusConnection *connection); void dbus_connection_return_message (DBusConnection *connection, @@ -241,7 +243,7 @@ void dbus_connection_unregister_object_path (DBusConnection const char **path); dbus_bool_t dbus_connection_list_registered (DBusConnection *connection, - const char **parent_path, + const char **parent_path, char ***child_entries); DBUS_END_DECLS; -- cgit From c9332907b035b52103c5569119d0a7c9fbcb76ac Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 22 Sep 2003 03:11:12 +0000 Subject: 2003-09-21 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_new): start implementing the proxy manager, didn't get very far. * dbus/dbus-bus.c (dbus_bus_add_match): new (dbus_bus_remove_match): new * glib/dbus-gproxy.c (dbus_gproxy_new_for_service): add a path_name argument; adjust the other not-yet-implemented gproxy constructors to be what I think they should be. --- dbus/dbus-bus.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- dbus/dbus-bus.h | 7 ++++ 2 files changed, 128 insertions(+), 1 deletion(-) (limited to 'dbus') diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 6d7cb82c..a8b9e452 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -681,7 +681,7 @@ dbus_bus_activate_service (DBusConnection *connection, } reply = dbus_connection_send_with_reply_and_block (connection, msg, - -1, error); + -1, error); dbus_message_unref (msg); if (reply == NULL) @@ -710,5 +710,125 @@ dbus_bus_activate_service (DBusConnection *connection, return TRUE; } +static void +send_no_return_values (DBusConnection *connection, + DBusMessage *msg, + DBusError *error) +{ + if (error) + { + /* Block to check success codepath */ + DBusMessage *reply; + + reply = dbus_connection_send_with_reply_and_block (connection, msg, + -1, error); + + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return; + } + + if (dbus_set_error_from_message (error, reply)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return; + } + + dbus_message_unref (reply); + } + else + { + /* Silently-fail nonblocking codepath */ + if (!dbus_connection_send (connection, msg, NULL)) + return; + } +} + +/** + * Adds a match rule to match messages going through the message bus. + * The "rule" argument is the string form of a match rule. + * + * If you pass #NULL for the error, this function will not + * block; the match thus won't be added until you flush the + * connection, and if there's an error adding the match + * (only possible error is lack of resources in the bus), + * you won't find out about it. + * + * If you pass non-#NULL for the error this function will + * block until it gets a reply. + * + * Normal API conventions would have the function return + * a boolean value indicating whether the error was set, + * but that would require blocking always to determine + * the return value. + * + * @param connection connection to the message bus + * @param rule textual form of match rule + * @param error location to store any errors + */ +void +dbus_bus_add_match (DBusConnection *connection, + const char *rule, + DBusError *error) +{ + DBusMessage *msg; + + msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "AddMatch"); + + if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (msg); + _DBUS_SET_OOM (error); + return; + } + + send_no_return_values (connection, msg, error); + + dbus_message_unref (msg); +} + +/** + * Removes a previously-added match rule "by value" (the most + * recently-added identical rule gets removed). The "rule" argument + * is the string form of a match rule. + * + * If you pass #NULL for the error, this function will not + * block; otherwise it will. See detailed explanation in + * docs for dbus_bus_add_match(). + * + * @param connection connection to the message bus + * @param rule textual form of match rule + * @param error location to store any errors + */ +void +dbus_bus_remove_match (DBusConnection *connection, + const char *rule, + DBusError *error) +{ + DBusMessage *msg; + + msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "RemoveMatch"); + + if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (msg); + _DBUS_SET_OOM (error); + return; + } + + send_no_return_values (connection, msg, error); + + dbus_message_unref (msg); +} /** @} */ diff --git a/dbus/dbus-bus.h b/dbus/dbus-bus.h index a62a746b..072b0c8e 100644 --- a/dbus/dbus-bus.h +++ b/dbus/dbus-bus.h @@ -59,6 +59,13 @@ dbus_bool_t dbus_bus_activate_service (DBusConnection *connection, dbus_uint32_t *reply, DBusError *error); +void dbus_bus_add_match (DBusConnection *connection, + const char *rule, + DBusError *error); +void dbus_bus_remove_match (DBusConnection *connection, + const char *rule, + DBusError *error); + DBUS_END_DECLS; #endif /* DBUS_BUS_H */ -- cgit From 52f275a7f43a78f981d0ccc85d5882ff4c356bdd Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 23 Sep 2003 23:47:09 +0000 Subject: 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_connect_signal): implement (dbus_gproxy_disconnect_signal): implement (dbus_gproxy_manager_remove_signal_match): implement (dbus_gproxy_manager_add_signal_match): implement (dbus_gproxy_oneway_call): implement --- dbus/dbus-message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dbus') diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 2ed421d7..824d85bf 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -4818,7 +4818,7 @@ decode_header_data (const DBusString *data, _dbus_verbose ("No path field provided\n"); return FALSE; } - /* FIXME make this optional, at least for method calls */ + /* FIXME make this optional, only for method calls */ if (fields[DBUS_HEADER_FIELD_INTERFACE].offset < 0) { _dbus_verbose ("No interface field provided\n"); -- cgit From 46c072e1136ca101aefd5fdae35c457899d55bbb Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 25 Sep 2003 08:50:14 +0000 Subject: 2003-09-25 Mark McLoughlin * doc/dbus-specification.sgml: don't require header fields to be 4-byte aligned and specify that fields should be distinguished from padding by the fact that zero is not a valid field name. * doc/TODO: remove re-alignment item and add item to doc the OBJECT_PATH type. * dbus/dbus-message.c: (HeaderField): rename the original member to value_offset and introduce a name_offset member to keep track of where the field actually begins. (adjust_field_offsets): remove. (append_int_field), (append_uint_field), (append_string_field): don't align the start of the header field to a 4-byte boundary. (get_next_field): impl finding the next marhsalled field after a given field. (re_align_field_recurse): impl re-aligning a number of already marshalled fields. (delete_field): impl deleting a field of any type and re-aligning any following fields. (delete_int_or_uint_field), (delete_string_field): remove. (set_int_field), (set_uint_field): no need to re-check that we have the correct type for the field. (set_string_field): ditto and impl re-aligning any following fields. (decode_header_data): update to take into account that the fields aren't 4-byte aligned any more and the new way to distinguish padding from header fields. Also, don't exit when there is too much header padding. (process_test_subdir): print the directory. (_dbus_message_test): add test to make sure a following field is re-aligned correctly after field deletion. * dbus/dbus-string.[ch]: (_dbus_string_insert_bytes): rename from insert_byte and allow the insert of multiple bytes. (_dbus_string_test): test inserting multiple bytes. * dbus/dbus-marshal.c: (_dbus_marshal_set_string): add warning note to docs about having to re-align any marshalled values following the string. * dbus/dbus-message-builder.c: (append_string_field), (_dbus_message_data_load): don't align the header field. * dbus/dbus-auth.c: (process_test_subdir): print the directory. * test/break-loader.c: (randomly_add_one_byte): upd. for insert_byte change. * test/data/invalid-messages/bad-header-field-alignment.message: new test case. * test/data/valid-messages/unknown-header-field.message: shove a dict in the unknown field. --- dbus/dbus-auth.c | 2 +- dbus/dbus-marshal.c | 4 + dbus/dbus-message-builder.c | 11 - dbus/dbus-message.c | 501 ++++++++++++++++++++++++++------------------ dbus/dbus-string.c | 35 ++-- dbus/dbus-string.h | 3 +- 6 files changed, 327 insertions(+), 229 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 90c72fd5..cdfd3bb2 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -2380,7 +2380,7 @@ process_test_subdir (const DBusString *test_base_dir, goto failed; } - printf ("Testing:\n"); + printf ("Testing %s:\n", subdir); next: while (_dbus_directory_get_next_file (dir, &filename, &error)) diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 3d6184e9..cb989891 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -395,6 +395,10 @@ _dbus_marshal_set_uint64 (DBusString *str, * an existing string or the wrong length will be deleted * and replaced with the new string. * + * Note: no attempt is made by this function to re-align + * any data which has been already marshalled after this + * string. Use with caution. + * * @param str the string to write the marshalled string to * @param offset the byte offset where string should be written * @param byte_order the byte order to use diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 7e2dff0d..c9dc8ca5 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -300,12 +300,6 @@ append_string_field (DBusString *dest, { int len; - if (!_dbus_string_align_length (dest, 4)) - { - _dbus_warn ("could not align field name\n"); - return FALSE; - } - if (!_dbus_string_append_byte (dest, field)) { _dbus_warn ("couldn't append field name byte\n"); @@ -710,11 +704,6 @@ _dbus_message_data_load (DBusString *dest, goto parse_failed; } - if (unalign) - unalign = FALSE; - else - _dbus_string_align_length (dest, 4); - if (!_dbus_string_append_byte (dest, field)) { _dbus_warn ("could not append header field name byte\n"); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 824d85bf..fe56e011 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -47,9 +47,8 @@ */ typedef struct { - int offset; /**< Offset to start of field (location of name of field - * for named fields) - */ + int name_offset; /**< Offset to name of field */ + int value_offset; /**< Offset to value of field */ } HeaderField; /** Offset to byte order from start of header */ @@ -183,26 +182,6 @@ append_header_padding (DBusMessage *message) return TRUE; } -static void -adjust_field_offsets (DBusMessage *message, - int offsets_after, - int delta) -{ - int i; - - if (delta == 0) - return; - - i = 0; - while (i <= DBUS_HEADER_FIELD_LAST) - { - if (message->header_fields[i].offset > offsets_after) - message->header_fields[i].offset += delta; - - ++i; - } -} - #ifdef DBUS_BUILD_TESTS /* tests-only until it's actually used */ static dbus_int32_t @@ -213,7 +192,7 @@ get_int_field (DBusMessage *message, _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); - offset = message->header_fields[field].offset; + offset = message->header_fields[field].value_offset; if (offset < 0) return -1; /* useless if -1 is a valid value of course */ @@ -233,7 +212,7 @@ get_uint_field (DBusMessage *message, _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); - offset = message->header_fields[field].offset; + offset = message->header_fields[field].value_offset; if (offset < 0) return -1; /* useless if -1 is a valid value of course */ @@ -252,7 +231,7 @@ get_string_field (DBusMessage *message, int offset; const char *data; - offset = message->header_fields[field].offset; + offset = message->header_fields[field].value_offset; _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); @@ -283,7 +262,7 @@ get_path_field_decomposed (DBusMessage *message, { int offset; - offset = message->header_fields[field].offset; + offset = message->header_fields[field].value_offset; _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); @@ -306,16 +285,12 @@ append_int_field (DBusMessage *message, int field, int value) { - int orig_len; - _dbus_assert (!message->locked); clear_header_padding (message); - orig_len = _dbus_string_get_length (&message->header); - - if (!_dbus_string_align_length (&message->header, 4)) - goto failed; + message->header_fields[field].name_offset = + _dbus_string_get_length (&message->header); if (!_dbus_string_append_byte (&message->header, field)) goto failed; @@ -326,7 +301,7 @@ append_int_field (DBusMessage *message, if (!_dbus_string_align_length (&message->header, 4)) goto failed; - message->header_fields[field].offset = + message->header_fields[field].value_offset = _dbus_string_get_length (&message->header); if (!_dbus_marshal_int32 (&message->header, message->byte_order, @@ -339,8 +314,10 @@ append_int_field (DBusMessage *message, return TRUE; failed: - message->header_fields[field].offset = -1; - _dbus_string_set_length (&message->header, orig_len); + _dbus_string_set_length (&message->header, + message->header_fields[field].name_offset); + message->header_fields[field].name_offset = -1; + message->header_fields[field].value_offset = -1; /* this must succeed because it was allocated on function entry and * DBusString doesn't ever realloc smaller @@ -356,16 +333,12 @@ append_uint_field (DBusMessage *message, int field, int value) { - int orig_len; - _dbus_assert (!message->locked); clear_header_padding (message); - orig_len = _dbus_string_get_length (&message->header); - - if (!_dbus_string_align_length (&message->header, 4)) - goto failed; + message->header_fields[field].name_offset = + _dbus_string_get_length (&message->header); if (!_dbus_string_append_byte (&message->header, field)) goto failed; @@ -376,7 +349,7 @@ append_uint_field (DBusMessage *message, if (!_dbus_string_align_length (&message->header, 4)) goto failed; - message->header_fields[field].offset = + message->header_fields[field].value_offset = _dbus_string_get_length (&message->header); if (!_dbus_marshal_uint32 (&message->header, message->byte_order, @@ -389,8 +362,10 @@ append_uint_field (DBusMessage *message, return TRUE; failed: - message->header_fields[field].offset = -1; - _dbus_string_set_length (&message->header, orig_len); + _dbus_string_set_length (&message->header, + message->header_fields[field].name_offset); + message->header_fields[field].name_offset = -1; + message->header_fields[field].value_offset = -1; /* this must succeed because it was allocated on function entry and * DBusString doesn't ever realloc smaller @@ -406,16 +381,12 @@ append_string_field (DBusMessage *message, int type, const char *value) { - int orig_len; - _dbus_assert (!message->locked); clear_header_padding (message); - orig_len = _dbus_string_get_length (&message->header); - - if (!_dbus_string_align_length (&message->header, 4)) - goto failed; + message->header_fields[field].name_offset = + _dbus_string_get_length (&message->header); if (!_dbus_string_append_byte (&message->header, field)) goto failed; @@ -426,7 +397,7 @@ append_string_field (DBusMessage *message, if (!_dbus_string_align_length (&message->header, 4)) goto failed; - message->header_fields[field].offset = + message->header_fields[field].value_offset = _dbus_string_get_length (&message->header); if (!_dbus_marshal_string (&message->header, message->byte_order, @@ -439,8 +410,10 @@ append_string_field (DBusMessage *message, return TRUE; failed: - message->header_fields[field].offset = -1; - _dbus_string_set_length (&message->header, orig_len); + _dbus_string_set_length (&message->header, + message->header_fields[field].name_offset); + message->header_fields[field].name_offset = -1; + message->header_fields[field].value_offset = -1; /* this must succeed because it was allocated on function entry and * DBusString doesn't ever realloc smaller @@ -451,71 +424,205 @@ append_string_field (DBusMessage *message, return FALSE; } -#ifdef DBUS_BUILD_TESTS -/* This isn't used, but building it when tests are enabled just to - * keep it compiling if we need it in future - */ -static void -delete_int_or_uint_field (DBusMessage *message, - int field) +static int +get_next_field (DBusMessage *message, + int field) { - int offset = message->header_fields[field].offset; + int offset = message->header_fields[field].name_offset; + int closest; + int i; + int retval = DBUS_HEADER_FIELD_INVALID; - _dbus_assert (!message->locked); - - if (offset < 0) - return; + i = 0; + closest = _DBUS_INT_MAX; + while (i < DBUS_HEADER_FIELD_LAST) + { + if (message->header_fields[i].name_offset > offset && + message->header_fields[i].name_offset < closest) + { + closest = message->header_fields[i].name_offset; + retval = i; + } + ++i; + } - clear_header_padding (message); - - /* The field typecode and name take up 4 bytes */ - _dbus_string_delete (&message->header, - offset - 4, - 8); + return retval; +} - message->header_fields[field].offset = -1; - - adjust_field_offsets (message, - offset - 4, - - 8); +static dbus_bool_t +re_align_field_recurse (DBusMessage *message, + int field, + int offset) +{ + int old_name_offset = message->header_fields[field].name_offset; + int old_value_offset = message->header_fields[field].value_offset; + int prev_padding, padding, delta; + int type; + int next_field; + int pos = offset; + + /* padding between the typecode byte and the value itself */ + prev_padding = old_value_offset - old_name_offset + 2; + + pos++; + type = _dbus_string_get_byte (&message->header, pos); + + pos++; + switch (type) + { + case DBUS_TYPE_NIL: + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + padding = 0; + break; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + padding = _DBUS_ALIGN_VALUE (pos, 4) - pos; + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + padding = _DBUS_ALIGN_VALUE (pos, 8) - pos; + break; + case DBUS_TYPE_NAMED: + case DBUS_TYPE_ARRAY: + case DBUS_TYPE_DICT: + _dbus_assert_not_reached ("no defined header fields may contain a named, array or dict value"); + break; + case DBUS_TYPE_INVALID: + default: + _dbus_assert_not_reached ("invalid type in marshalled header"); + break; + } + + delta = padding - prev_padding; + if (delta > 0) + { + if (!_dbus_string_insert_bytes (&message->header, pos, delta, 0)) + return FALSE; + } + else if (delta < 0) + { + _dbus_string_delete (&message->header, pos, -delta); + } + + next_field = get_next_field (message, field); + if (next_field != DBUS_HEADER_FIELD_INVALID) + { + int next_offset = message->header_fields[next_field].name_offset; + + _dbus_assert (next_offset > 0); + + if (!re_align_field_recurse (message, field, + pos + padding + (next_offset - old_value_offset))) + goto failed; + } + else + { + if (!append_header_padding (message)) + goto failed; + } + + message->header_fields[field].name_offset = offset; + message->header_fields[field].value_offset = pos + padding; + + return TRUE; + + failed: + if (delta > 0) + { + _dbus_string_delete (&message->header, pos, delta); + } + else if (delta < 0) + { + /* this must succeed because it was allocated on function entry and + * DBusString doesn't ever realloc smaller + */ + _dbus_string_insert_bytes (&message->header, pos, -delta, 0); + } - append_header_padding (message); + return FALSE; } -#endif -static void -delete_string_field (DBusMessage *message, - int field) +static dbus_bool_t +delete_field (DBusMessage *message, + int field) { - int offset = message->header_fields[field].offset; - int len; - int delete_len; - + int offset = message->header_fields[field].name_offset; + int next_field; + _dbus_assert (!message->locked); if (offset < 0) - return; + return FALSE; clear_header_padding (message); - - get_string_field (message, field, &len); - - /* The field typecode and name take up 4 bytes, and the nul - * termination is 1 bytes, string length integer is 4 bytes - */ - delete_len = 4 + 4 + 1 + len; - - _dbus_string_delete (&message->header, - offset - 4, - delete_len); - message->header_fields[field].offset = -1; - - adjust_field_offsets (message, - offset - 4, - - delete_len); + next_field = get_next_field (message, field); + if (next_field == DBUS_HEADER_FIELD_INVALID) + { + _dbus_string_set_length (&message->header, offset); - append_header_padding (message); + message->header_fields[field].name_offset = -1; + message->header_fields[field].value_offset = -1; + + /* this must succeed because it was allocated on function entry and + * DBusString doesn't ever realloc smaller + */ + if (!append_header_padding (message)) + _dbus_assert_not_reached ("failed to reappend header padding"); + + return TRUE; + } + else + { + DBusString deleted; + int next_offset = message->header_fields[next_field].name_offset; + + _dbus_assert (next_offset > 0); + + if (!_dbus_string_init (&deleted)) + goto failed; + + if (!_dbus_string_move_len (&message->header, + offset, next_offset - offset, + &deleted, 0)) + { + _dbus_string_free (&deleted); + goto failed; + } + + /* appends the header padding */ + if (!re_align_field_recurse (message, next_field, offset)) + { + /* this must succeed because it was allocated on function entry and + * DBusString doesn't ever realloc smaller + */ + if (!_dbus_string_copy (&deleted, 0, &message->header, offset)) + _dbus_assert_not_reached ("failed to revert to original field"); + + _dbus_string_free (&deleted); + goto failed; + } + + _dbus_string_free (&deleted); + + message->header_fields[field].name_offset = -1; + message->header_fields[field].value_offset = -1; + + return TRUE; + + failed: + /* this must succeed because it was allocated on function entry and + * DBusString doesn't ever realloc smaller + */ + if (!append_header_padding (message)) + _dbus_assert_not_reached ("failed to reappend header padding"); + + return FALSE; + } } #ifdef DBUS_BUILD_TESTS @@ -524,20 +631,14 @@ set_int_field (DBusMessage *message, int field, int value) { - int offset = message->header_fields[field].offset; + int offset = message->header_fields[field].value_offset; _dbus_assert (!message->locked); if (offset < 0) { /* need to append the field */ - - switch (field) - { - default: - _dbus_assert_not_reached ("appending an int field we don't support appending"); - return FALSE; - } + return append_int_field (message, field, value); } else { @@ -555,23 +656,14 @@ set_uint_field (DBusMessage *message, int field, dbus_uint32_t value) { - int offset = message->header_fields[field].offset; + int offset = message->header_fields[field].value_offset; _dbus_assert (!message->locked); if (offset < 0) { /* need to append the field */ - - switch (field) - { - case DBUS_HEADER_FIELD_REPLY_SERIAL: - return append_uint_field (message, field, value); - - default: - _dbus_assert_not_reached ("appending a uint field we don't support appending"); - return FALSE; - } + return append_uint_field (message, field, value); } else { @@ -589,7 +681,7 @@ set_string_field (DBusMessage *message, int type, const char *value) { - int offset = message->header_fields[field].offset; + int offset = message->header_fields[field].value_offset; _dbus_assert (!message->locked); _dbus_assert (value != NULL); @@ -597,52 +689,59 @@ set_string_field (DBusMessage *message, if (offset < 0) { /* need to append the field */ - - switch (field) - { - case DBUS_HEADER_FIELD_PATH: - case DBUS_HEADER_FIELD_SENDER_SERVICE: - case DBUS_HEADER_FIELD_INTERFACE: - case DBUS_HEADER_FIELD_MEMBER: - case DBUS_HEADER_FIELD_ERROR_NAME: - case DBUS_HEADER_FIELD_SERVICE: - return append_string_field (message, field, type, value); - - default: - _dbus_assert_not_reached ("appending a string field we don't support appending"); - return FALSE; - } + return append_string_field (message, field, type, value); } else { DBusString v; - int old_len; - int new_len; + char *old_value; + int next_field; + int next_offset; int len; clear_header_padding (message); - - old_len = _dbus_string_get_length (&message->header); + + old_value = _dbus_demarshal_string (&message->header, + message->byte_order, + offset, + &next_offset); + if (!old_value) + goto failed; len = strlen (value); - + _dbus_string_init_const_len (&v, value, len + 1); /* include nul */ if (!_dbus_marshal_set_string (&message->header, message->byte_order, - offset, &v, - len)) - goto failed; - - new_len = _dbus_string_get_length (&message->header); + offset, &v, len)) + { + dbus_free (old_value); + goto failed; + } - adjust_field_offsets (message, - offset, - new_len - old_len); + next_field = get_next_field (message, field); + if (next_field != DBUS_HEADER_FIELD_INVALID) + { + /* re-appends the header padding */ + if (!re_align_field_recurse (message, next_field, next_offset)) + { + len = strlen (old_value); + + _dbus_string_init_const_len (&v, old_value, + len + 1); /* include nul */ + if (!_dbus_marshal_set_string (&message->header, + message->byte_order, + offset, &v, len)) + _dbus_assert_not_reached ("failed to revert to original string"); + + dbus_free (old_value); + goto failed; + } + } + + dbus_free (old_value); - if (!append_header_padding (message)) - goto failed; - return TRUE; failed: @@ -983,7 +1082,8 @@ dbus_message_new_empty_header (void) i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { - message->header_fields[i].offset = -1; + message->header_fields[i].name_offset = -1; + message->header_fields[i].value_offset = -1; ++i; } @@ -1281,7 +1381,7 @@ dbus_message_copy (const DBusMessage *message) for (i = 0; i <= DBUS_HEADER_FIELD_LAST; i++) { - retval->header_fields[i].offset = message->header_fields[i].offset; + retval->header_fields[i] = message->header_fields[i]; } return retval; @@ -1390,7 +1490,7 @@ dbus_message_set_path (DBusMessage *message, if (object_path == NULL) { - delete_string_field (message, DBUS_HEADER_FIELD_PATH); + delete_field (message, DBUS_HEADER_FIELD_PATH); return TRUE; } else @@ -1464,7 +1564,7 @@ dbus_message_set_interface (DBusMessage *message, if (interface == NULL) { - delete_string_field (message, DBUS_HEADER_FIELD_INTERFACE); + delete_field (message, DBUS_HEADER_FIELD_INTERFACE); return TRUE; } else @@ -1512,7 +1612,7 @@ dbus_message_set_member (DBusMessage *message, if (member == NULL) { - delete_string_field (message, DBUS_HEADER_FIELD_MEMBER); + delete_field (message, DBUS_HEADER_FIELD_MEMBER); return TRUE; } else @@ -1559,8 +1659,7 @@ dbus_message_set_error_name (DBusMessage *message, if (error_name == NULL) { - delete_string_field (message, - DBUS_HEADER_FIELD_ERROR_NAME); + delete_field (message, DBUS_HEADER_FIELD_ERROR_NAME); return TRUE; } else @@ -1604,7 +1703,7 @@ dbus_message_set_destination (DBusMessage *message, if (destination == NULL) { - delete_string_field (message, DBUS_HEADER_FIELD_SERVICE); + delete_field (message, DBUS_HEADER_FIELD_SERVICE); return TRUE; } else @@ -4081,8 +4180,7 @@ dbus_message_set_sender (DBusMessage *message, if (sender == NULL) { - delete_string_field (message, - DBUS_HEADER_FIELD_SENDER_SERVICE); + delete_field (message, DBUS_HEADER_FIELD_SENDER_SERVICE); return TRUE; } else @@ -4550,7 +4648,7 @@ decode_string_field (const DBusString *data, _dbus_assert (header_field != NULL); _dbus_assert (field_data != NULL); - if (header_field->offset >= 0) + if (header_field->name_offset >= 0) { _dbus_verbose ("%s field provided twice\n", _dbus_header_field_to_string (field)); @@ -4575,12 +4673,13 @@ decode_string_field (const DBusString *data, _dbus_string_init_const (field_data, _dbus_string_get_const_data (data) + string_data_pos); - header_field->offset = _DBUS_ALIGN_VALUE (pos, 4); + header_field->name_offset = pos; + header_field->value_offset = _DBUS_ALIGN_VALUE (pos, 4); #if 0 _dbus_verbose ("Found field %s at offset %d\n", _dbus_header_field_to_string (field), - header_field->offset); + header_field->value_offset); #endif return TRUE; @@ -4609,29 +4708,18 @@ decode_header_data (const DBusString *data, i = 0; while (i <= DBUS_HEADER_FIELD_LAST) { - fields[i].offset = -1; + fields[i].name_offset = -1; + fields[i].value_offset = -1; ++i; } - /* Now handle the named fields. A real named field is at least 1 - * byte for the name, plus a type code (1 byte) plus padding, plus - * the field value. So if we have less than 8 bytes left, it must - * be alignment padding, not a field. While >= 8 bytes can't be - * entirely alignment padding. - */ pos = 16; - while ((pos + 7) < header_len) + while (pos < header_len) { - pos = _DBUS_ALIGN_VALUE (pos, 4); - - if ((pos + 1) > header_len) - { - _dbus_verbose ("not enough space remains in header for header field value\n"); - return FALSE; - } - field = _dbus_string_get_byte (data, pos); - pos += 1; + if (field == DBUS_HEADER_FIELD_INVALID) + break; /* Must be padding */ + pos++; if (!_dbus_marshal_validate_type (data, pos, &type, &pos)) { @@ -4737,7 +4825,7 @@ decode_header_data (const DBusString *data, * type. */ - if (fields[field].offset >= 0) + if (fields[field].name_offset >= 0) { _dbus_verbose ("path field provided twice\n"); return FALSE; @@ -4748,15 +4836,16 @@ decode_header_data (const DBusString *data, return FALSE; } - fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4); + fields[field].name_offset = pos; + fields[field].value_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].offset, + fields[field].value_offset, _dbus_string_get_length (data) - - fields[field].offset); + fields[field].value_offset); if (strcmp (s, DBUS_PATH_ORG_FREEDESKTOP_LOCAL) == 0) { _dbus_verbose ("Message is on the local path\n"); @@ -4765,11 +4854,11 @@ decode_header_data (const DBusString *data, } _dbus_verbose ("Found path at offset %d\n", - fields[field].offset); + fields[field].value_offset); break; case DBUS_HEADER_FIELD_REPLY_SERIAL: - if (fields[field].offset >= 0) + if (fields[field].name_offset >= 0) { _dbus_verbose ("reply field provided twice\n"); return FALSE; @@ -4781,10 +4870,11 @@ decode_header_data (const DBusString *data, return FALSE; } - fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4); + fields[field].name_offset = pos; + fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4); _dbus_verbose ("Found reply serial at offset %d\n", - fields[field].offset); + fields[field].value_offset); break; default: @@ -4798,7 +4888,11 @@ decode_header_data (const DBusString *data, if (pos < header_len) { /* Alignment padding, verify that it's nul */ - _dbus_assert ((header_len - pos) < 8); + if ((header_len - pos) >= 8) + { + _dbus_verbose ("too much header alignment padding\n"); + return FALSE; + } if (!_dbus_string_validate_nul (data, pos, (header_len - pos))) @@ -4813,25 +4907,25 @@ decode_header_data (const DBusString *data, { case DBUS_MESSAGE_TYPE_SIGNAL: case DBUS_MESSAGE_TYPE_METHOD_CALL: - if (fields[DBUS_HEADER_FIELD_PATH].offset < 0) + if (fields[DBUS_HEADER_FIELD_PATH].value_offset < 0) { _dbus_verbose ("No path field provided\n"); return FALSE; } /* FIXME make this optional, only for method calls */ - if (fields[DBUS_HEADER_FIELD_INTERFACE].offset < 0) + if (fields[DBUS_HEADER_FIELD_INTERFACE].value_offset < 0) { _dbus_verbose ("No interface field provided\n"); return FALSE; } - if (fields[DBUS_HEADER_FIELD_MEMBER].offset < 0) + if (fields[DBUS_HEADER_FIELD_MEMBER].value_offset < 0) { _dbus_verbose ("No member field provided\n"); return FALSE; } break; case DBUS_MESSAGE_TYPE_ERROR: - if (fields[DBUS_HEADER_FIELD_ERROR_NAME].offset < 0) + if (fields[DBUS_HEADER_FIELD_ERROR_NAME].value_offset < 0) { _dbus_verbose ("No error-name field provided\n"); return FALSE; @@ -6069,7 +6163,7 @@ process_test_subdir (const DBusString *test_base_dir, goto failed; } - printf ("Testing:\n"); + printf ("Testing %s:\n", subdir); next: while (_dbus_directory_get_next_file (dir, &filename, &error)) @@ -6432,11 +6526,14 @@ _dbus_message_test (const char *test_data_dir) _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface", "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")); + /* string length including nul byte not a multiple of 4 */ + dbus_message_set_sender (message, "org.foo.bar1"); + _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1")); + dbus_message_set_reply_serial (message, 5678); dbus_message_set_sender (message, NULL); - _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar")); + _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1")); _dbus_assert (dbus_message_get_serial (message) == 1234); + _dbus_assert (dbus_message_get_reply_serial (message) == 5678); _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); _dbus_assert (dbus_message_get_no_reply (message) == FALSE); diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 40363686..628cf861 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -562,26 +562,30 @@ _dbus_string_get_byte (const DBusString *str, } /** - * Inserts the given byte at the given position. + * Inserts a number of bytes of a given value at the + * given position. * * @param str the string * @param i the position + * @param n_bytes number of bytes * @param byte the value to insert * @returns #TRUE on success */ dbus_bool_t -_dbus_string_insert_byte (DBusString *str, - int i, - unsigned char byte) +_dbus_string_insert_bytes (DBusString *str, + int i, + int n_bytes, + unsigned char byte) { DBUS_STRING_PREAMBLE (str); _dbus_assert (i <= real->len); _dbus_assert (i >= 0); + _dbus_assert (n_bytes > 0); - if (!open_gap (1, real, i)) + if (!open_gap (n_bytes, real, i)) return FALSE; - real->str[i] = byte; + memset (real->str + i, byte, n_bytes); return TRUE; } @@ -3572,23 +3576,26 @@ _dbus_string_test (void) _dbus_string_set_byte (&str, 1, 'q'); _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q'); - if (!_dbus_string_insert_byte (&str, 0, 255)) + if (!_dbus_string_insert_bytes (&str, 0, 1, 255)) _dbus_assert_not_reached ("can't insert byte"); - if (!_dbus_string_insert_byte (&str, 2, 'Z')) + if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z')) _dbus_assert_not_reached ("can't insert byte"); - if (!_dbus_string_insert_byte (&str, _dbus_string_get_length (&str), 'W')) + if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W')) _dbus_assert_not_reached ("can't insert byte"); _dbus_assert (_dbus_string_get_byte (&str, 0) == 255); _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H'); _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z'); - _dbus_assert (_dbus_string_get_byte (&str, 3) == 'q'); - _dbus_assert (_dbus_string_get_byte (&str, 4) == 'l'); - _dbus_assert (_dbus_string_get_byte (&str, 5) == 'l'); - _dbus_assert (_dbus_string_get_byte (&str, 6) == 'o'); - _dbus_assert (_dbus_string_get_byte (&str, 7) == 'W'); + _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z'); + _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z'); + _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z'); + _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q'); + _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l'); + _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l'); + _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o'); + _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W'); _dbus_string_free (&str); diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index 70e83b33..0b7be8b0 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -72,8 +72,9 @@ void _dbus_string_set_byte (DBusString *str, unsigned char byte); unsigned char _dbus_string_get_byte (const DBusString *str, int start); -dbus_bool_t _dbus_string_insert_byte (DBusString *str, +dbus_bool_t _dbus_string_insert_bytes (DBusString *str, int i, + int n_bytes, unsigned char byte); dbus_bool_t _dbus_string_steal_data (DBusString *str, char **data_return); -- cgit