-- cgit v1.2.1 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 --- ChangeLog | 15 +++ 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 + 11 files changed, 532 insertions(+), 44 deletions(-) create mode 100644 dbus/dbus-objectid.c create mode 100644 dbus/dbus-objectid.h diff --git a/ChangeLog b/ChangeLog index e6840083..527ad1fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +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 + 2003-06-29 Havoc Pennington * mono/Test.cs (class Test): fire up a main loop and run it 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 v1.2.1 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. --- ChangeLog | 1258 ++++++++++++++++++++------------------- 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 + 13 files changed, 1155 insertions(+), 624 deletions(-) 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 diff --git a/ChangeLog b/ChangeLog index 527ad1fd..9ed9055c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,12 +1,22 @@ +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. + 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 + 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 + (_dbus_marshal_validate_arg): consolidate identical cases, and handle DBUS_TYPE_OBJECT_ID * dbus/dbus-objectid.c: new file with DBusObjectID data type. @@ -26,7 +36,7 @@ 2003-07-01 Havoc Pennington - * doc/dbus-specification.sgml: clarify the format of a type code, + * doc/dbus-specification.sgml: clarify the format of a type code, change suggested by Jim Blandy 2003-06-29 Miloslav Trmac @@ -44,7 +54,7 @@ of %c%c%c%c. (dbus_message_new): Remove obsolete @todo. - * dbus/dbus-marshal.c (_dbus_marshal_set_int64) + * dbus/dbus-marshal.c (_dbus_marshal_set_int64) (_dbus_marshal_set_uint64): Fix comment. * dbus/dbus-message.c (append_int_field, append_uint_field): Don't @@ -77,7 +87,7 @@ (Message.Message): * gcj/org/freedesktop/dbus/natMessage.cc: Fix the build system. - + 2003-06-22 Havoc Pennington * mono/Connection.cs: add more bindings @@ -87,13 +97,13 @@ 2003-06-22 Havoc Pennington - * mono/Connection.cs, mono/DBus.cs, mono/Error.cs: + * mono/Connection.cs, mono/DBus.cs, mono/Error.cs: Start wrapping more stuff. 2003-06-22 Havoc Pennington * mono/Message.cs: implement Message.Wrap() that ensures we only - have a single C# wrapper per DBusMessage, assuming it works which + have a single C# wrapper per DBusMessage, assuming it works which it probably doesn't. * dbus/dbus-message.c (dbus_message_allocate_data_slot): new @@ -105,9 +115,9 @@ * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_unref) (_dbus_data_slot_allocator_alloc): rework these to keep a - reference count on each slot and automatically manage a global + reference count on each slot and automatically manage a global slot ID variable passed in by address - + * bus/bus.c: convert to new dataslot API * dbus/dbus-bus.c: convert to new dataslot API @@ -133,9 +143,9 @@ 2003-06-22 Havoc Pennington - * mono/*, gcj/*, configure.in, Makefile.am: - Check in makefiles and subdirs for mono and gcj bindings. - Neither binding actually exists, just trying to get through + * mono/*, gcj/*, configure.in, Makefile.am: + Check in makefiles and subdirs for mono and gcj bindings. + Neither binding actually exists, just trying to get through all the build and other boring bits. 2003-06-21 Philip Blundell @@ -146,7 +156,7 @@ 2003-06-20 Anders Carlsson - * dbus/dbus-transport-unix.c (unix_handle_watch): Check + * dbus/dbus-transport-unix.c (unix_handle_watch): Check for hangup and error after checking read so we won't discard pending data if both hangup and read are set. @@ -155,9 +165,9 @@ * tools/dbus-print-message.c (print_message): Handle BOOLEAN. * tools/dbus-send.c: Accept both --system and --session. - + * tools/dbus-monitor.c: Same here. - + 2003-06-19 Anders Carlsson * glib/dbus-glib.h: Fix so that dbus-glib.h can be used @@ -201,13 +211,13 @@ toggle as an argument, implement abstract namespace support (_dbus_listen_unix_socket): ditto - * configure.in: add --enable-abstract-sockets and implement + * configure.in: add --enable-abstract-sockets and implement a configure check for autodetection of the right value. 2003-06-01 Havoc Pennington - * tools/dbus-cleanup-sockets.c: add utility to clean up sockets - in /tmp (though on Linux this will end up being useless, + * tools/dbus-cleanup-sockets.c: add utility to clean up sockets + in /tmp (though on Linux this will end up being useless, when we add abstract namespace support) * configure.in: define DBUS_SESSION_SOCKET_DIR in addition to @@ -226,29 +236,29 @@ * tools/dbus-send.c: Don't exit with an error code if --help was passed. Default to using the session bus instead of the system one. - - * tools/dbus-launch.c: Ditto. + + * tools/dbus-launch.c: Ditto. * tools/dbus-monitor.c: Ditto. * tools/dbus-send.1: Update with new arguments. - + * tools/dbus-launch.c: Emit code to export variables. New arguments -s and -c to specify shell syntax, and a bit of code to autodetect syntax. Also, allow specifying a program to run. - + * tools/dbus-launch.1: Update with new arguments. - + * tools/dbus-send.1: Ditto. * tools/dbus-monitor.1: Ditto. - + 2003-05-17 Havoc Pennington * bus/config-parser.c (merge_included): merge in policies from child configuration file. - * bus/policy.c (bus_policy_merge): function to merge two policies + * bus/policy.c (bus_policy_merge): function to merge two policies together 2003-05-16 Havoc Pennington @@ -257,12 +267,12 @@ * tools/dbus-send.c: add --print-reply command line option - * tools/dbus-print-message.h (print_message): new util function + * tools/dbus-print-message.h (print_message): new util function shared by dbus-send and dbus-monitor * tools/dbus-monitor.c (handler_func): exit on disconnect - * dbus/dbus-transport-unix.c (do_reading): if the transport is + * dbus/dbus-transport-unix.c (do_reading): if the transport is disconnected, don't try to use the read_watch * dbus/dbus-watch.c (dbus_watch_get_enabled): assert watch != NULL @@ -301,7 +311,7 @@ check" as it broke distcheck * bus/Makefile.am (install-data-hook): create /etc/dbus-1/system.d - + 2003-05-13 James Willcox * configure.in: @@ -323,18 +333,18 @@ 2003-05-11 Havoc Pennington - * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid calling _dbus_marshal_validate_arg() for every byte in a byte array, etc. - * dbus/dbus-message-handler.c: use atomic reference counting to + * dbus/dbus-message-handler.c: use atomic reference counting to reduce number of locks slightly; the global lock in here sucks * dbus/dbus-connection.c (_dbus_connection_update_dispatch_status_and_unlock): variant of update_dispatch_status that can be called with lock held; then use in a couple places to reduce locking/unlocking - (dbus_connection_send): hold the lock over the whole function + (dbus_connection_send): hold the lock over the whole function instead of acquiring it twice. * dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM @@ -350,7 +360,7 @@ * dbus/dbus-list.c (_dbus_list_find_last): new function * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): - change to use a struct for the atomic type; fix docs, + change to use a struct for the atomic type; fix docs, they return value before increment, not after increment. * dbus/dbus-string.c (_dbus_string_append_4_aligned) @@ -367,8 +377,8 @@ * dbus/dbus-string.c (_dbus_string_move): just call _dbus_string_move_len - (_dbus_string_move_len): add a special case for moving - an entire string into an empty string; we can just + (_dbus_string_move_len): add a special case for moving + an entire string into an empty string; we can just swap the string data instead of doing any reallocs. (_dbus_string_init_preallocated): new function @@ -379,14 +389,14 @@ UTF-8 validation as hot spots. 20% of lock contention eliminated with dbus_atomic_inc/dec implementation on x86. Much remaining contention is global mempool locks for GList and DBusList. - + * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): add x86 implementation * dbus/dbus-connection.c (struct DBusConnection): use - dbus_atomic_t for the reference count + dbus_atomic_t for the reference count - * dbus/dbus-message.c (struct DBusMessage): declare + * dbus/dbus-message.c (struct DBusMessage): declare dbus_atomic_t values as volatile * configure.in: code to detect ability to use atomic integer @@ -395,22 +405,22 @@ * dbus/dbus-internals.c (_dbus_verbose_real): call getpid every time, tired of it being wrong in threads and forked processes - * glib/test-profile.c: a little program to bounce messages back + * glib/test-profile.c: a little program to bounce messages back and forth between threads and eat CPU * dbus/dbus-connection.c: add debug spew macros for debugging - thread locks; include config.h at top; fix deadlock in + thread locks; include config.h at top; fix deadlock in dbus_connection_flush() 2003-05-08 Havoc Pennington * dbus/dbus-spawn.c: s/_exit/exit/ because it was keeping gcov - data from getting written, and there wasn't a good reason to + data from getting written, and there wasn't a good reason to use _exit really. * test/decode-gcov.c (mark_inside_dbus_build_tests): don't count dbus_verbose lines in test coverage - (main): add list of functions sorted by # of untested blocks + (main): add list of functions sorted by # of untested blocks to the coverage report * dbus/dbus-mempool.c: put some test-only code in DBUS_BUILD_TESTS @@ -451,14 +461,14 @@ 2003-05-04 Havoc Pennington - * dbus-glib-1.pc.in (Requires): fix dependencies, from + * dbus-glib-1.pc.in (Requires): fix dependencies, from Anders Gustafsson 2003-05-04 Havoc Pennington * tools/dbus-launch.c: implement - * bus/main.c (main), bus/bus.c (bus_context_new): + * bus/main.c (main), bus/bus.c (bus_context_new): implement --print-pid and --fork 2003-05-03 Havoc Pennington @@ -475,7 +485,7 @@ * tools/Makefile.am, tools/dbus-launch.c, tools/dbus-launch.1: add dbus-launch utility to launch the bus from a shell script. Didn't actually implement dbus-launch yet, it's just a placeholder still. - + 2003-05-03 Havoc Pennington * bus/Makefile.am, bus/dbus-daemon-1.1.in: man page for the @@ -485,7 +495,7 @@ 2003-05-03 Havoc Pennington - * tools/Makefile.am, tools/dbus-send.1, tools/dbus-monitor.1: + * tools/Makefile.am, tools/dbus-send.1, tools/dbus-monitor.1: add some man pages 2003-05-03 Colin Walters @@ -536,7 +546,7 @@ * dbus/dbus.h: add "you have to define DBUS_API_SUBJECT_TO_CHANGE to use this library" to be sure people have the right expectations. - + 2003-04-28 Havoc Pennington * configure.in: add --enable-docs which by default is auto yes if @@ -552,14 +562,14 @@ * NEWS: update * bus/system.conf.in: add system.d - + * dbus/dbus-userdb.c (_dbus_user_database_lookup): fix bug when username was provided but not uid * bus/config-parser.c (struct BusConfigParser): keep track of - whether the parser is toplevel or was included; change some + whether the parser is toplevel or was included; change some of the error handling if it's included. - + 2003-04-27 Havoc Pennington Unbreak my code... @@ -567,7 +577,7 @@ * dbus/dbus-transport.c (_dbus_transport_get_dispatch_status): report correct status if we finish processing authentication inside this function. - + * bus/activation.c (try_send_activation_failure): use bus_transaction_send_error_reply @@ -576,7 +586,7 @@ * bus/bus.c (bus_context_check_security_policy): implement restriction here that inactive connections can only send the - hello message. Also, allow bus driver to send anything to + hello message. Also, allow bus driver to send anything to any recipient. * bus/connection.c (bus_connection_complete): create the @@ -595,7 +605,7 @@ 2003-04-25 Havoc Pennington test suite is slightly hosed at the moment, will fix soon - + * bus/connection.c (bus_connections_expire_incomplete): fix to properly disable the timeout when required (bus_connection_set_name): check whether we can remove incomplete @@ -605,7 +615,7 @@ probably still broken. * bus/services.c (bus_registry_acquire_service): implement max - number of services owned, and honor allow/deny rules on which + number of services owned, and honor allow/deny rules on which services a connection can own. * bus/connection.c (bus_connection_get_policy): report errors here @@ -627,19 +637,19 @@ * test/data/valid-config-files/basic.conf: add tags to this test - + * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement tag in configuration file. - + 2003-04-24 Havoc Pennington * bus/dispatch.c: somehow missed some name_is - * dbus/dbus-timeout.c (_dbus_timeout_set_enabled) + * dbus/dbus-timeout.c (_dbus_timeout_set_enabled) (_dbus_timeout_set_interval): new * bus/connection.c (bus_connections_setup_connection): record time - when each connection is first set up, and expire them after the + when each connection is first set up, and expire them after the auth timeout passes. 2003-04-24 Havoc Pennington @@ -687,7 +697,7 @@ 2003-04-22 Havoc Pennington * dbus/dbus-message.c, dbus/dbus-marshal.c: add 64-bit integer - support, and do some code cleanups to share more code and + support, and do some code cleanups to share more code and speed up array marshal/demarshal. * dbus-1.0.pc.in (Cflags): put libdir include file in cflags @@ -703,7 +713,7 @@ to use proper type for rply field * test/data/invalid-messages: add tests for below validation - + * dbus/dbus-message.c (decode_header_data): validate field types, and validate that named fields are valid names (decode_name_field): consider messages in the @@ -713,7 +723,7 @@ 2003-04-19 Havoc Pennington - * bus/driver.c (bus_driver_handle_hello): check limits and + * bus/driver.c (bus_driver_handle_hello): check limits and return an error if they are exceeded. * bus/connection.c: maintain separate lists of active and inactive @@ -732,7 +742,7 @@ * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): fix some memleaks - * dbus/dbus-keyring.c (add_new_key): fix a memleak, and + * dbus/dbus-keyring.c (add_new_key): fix a memleak, and on realloc be sure to update the pointer in the keyring * dbus/dbus-string.c (_dbus_string_zero): compensate for align @@ -756,7 +766,7 @@ server. 2003-04-18 Havoc Pennington - + * dbus/dbus-mainloop.c (_dbus_loop_iterate): fix UMR in verbose debug spew @@ -768,7 +778,7 @@ * bus/Makefile.am (TESTS_ENVIRONMENT): put DBUS_TEST_HOMEDIR in the environment - + * bus/dispatch.c (bus_dispatch_sha1_test): actually load sha1 config file so we test the right thing @@ -811,14 +821,14 @@ * dbus/dbus-message.h: change message serials to unsigned * dbus/dbus-connection.c: adapt to message serials being unsigned - + 2003-04-15 Havoc Pennington - * bus/bus.c: create and keep around a shared DBusUserDatabase + * bus/bus.c: create and keep around a shared DBusUserDatabase object. * bus/connection.c (bus_connection_get_groups): don't cache - groups for user in the connection object, since user database + groups for user in the connection object, since user database object now does that. 2003-04-16 Havoc Pennington @@ -828,12 +838,12 @@ (_dbus_message_loader_putback_message_link): put back a popped link * dbus/dbus-connection.c - (dbus_connection_set_max_live_messages_size): rename + (dbus_connection_set_max_live_messages_size): rename max_received_size - (dbus_connection_get_outgoing_size): get size of outgoing + (dbus_connection_get_outgoing_size): get size of outgoing queue (_dbus_connection_set_connection_counter): remove this cruft - + 2003-04-14 Havoc Pennington * dbus/dbus-userdb.c: user database abstraction, mostly to get @@ -845,17 +855,17 @@ test always uses EXTERNAL when available. * configure.in, - test/data/valid-config-files/debug-allow-all-sha1.conf.in: + test/data/valid-config-files/debug-allow-all-sha1.conf.in: add conf file that requires use of sha1 auth 2003-04-13 Havoc Pennington - + * tools/dbus-send.c, tools/dbus-monitor.c: two utility programs from Philip Blundell to send messages and monitor them. - + 2003-04-13 Havoc Pennington - * dbus/dbus-mainloop.c: fix some reentrancy issues by refcounting + * dbus/dbus-mainloop.c: fix some reentrancy issues by refcounting callbacks * test/data/valid-config-files/debug-allow-all.conf.in: allow all @@ -863,11 +873,11 @@ * dbus/dbus-transport.c (_dbus_transport_get_dispatch_status): fix to only recover unused bytes if we're already authenticated - (_dbus_transport_get_is_authenticated): fix to still mark us + (_dbus_transport_get_is_authenticated): fix to still mark us authenticated if there are unused bytes. * bus/dispatch.c: implement security policy checking - + * bus/connection.c (bus_transaction_send_from_driver): new * bus/bus.c (bus_context_check_security_policy): new @@ -885,7 +895,7 @@ 2003-04-13 Havoc Pennington * bus/config-parser.c: Load up the BusPolicy and BusPolicyRules - + * dbus/dbus-sysdeps.c (_dbus_get_user_id): new function * bus/policy.c (bus_policy_append_mandatory_rule) @@ -900,7 +910,7 @@ the pid/gid/uid, just for paranoia. * test/break-loader.c (randomly_do_n_things): find a byte - containing a type code, and randomly change it to a different + containing a type code, and randomly change it to a different type code. 2003-04-12 Havoc Pennington @@ -908,7 +918,7 @@ * bus/policy.h: change BusPolicy to be the thing from the config file, and rename old BusPolicy to BusClientPolicy - * bus/bus.c, bus/connection.c, bus/config-parser.c: change to + * bus/bus.c, bus/connection.c, bus/config-parser.c: change to match change in how policy works * dbus/dbus-internals.h: mark assert_not_reached as @@ -916,7 +926,7 @@ 2003-04-11 Havoc Pennington - * doc/dbus-specification.sgml: fix a spot with the wrong name for + * doc/dbus-specification.sgml: fix a spot with the wrong name for the broadcast service. Use boolean return for ServiceExists. 2003-04-11 Havoc Pennington @@ -991,7 +1001,7 @@ we don't successfully create the service after all. Don't remove pending activation if the function fails. - * dbus/dbus-list.c (_dbus_list_insert_before_link) + * dbus/dbus-list.c (_dbus_list_insert_before_link) (_dbus_list_insert_after_link): new code to facilitate services.c fixes @@ -1000,30 +1010,30 @@ into a hash table. * bus/connection.c (bus_transaction_add_cancel_hook): new function - allowing us to put custom hooks in a transaction to be used for + allowing us to put custom hooks in a transaction to be used for cancelling said transaction * doc/dbus-specification.sgml: add some discussion of secondary service owners, and disallow zero-length service names * bus/services.c (bus_registry_acquire_service): new function, - splits out part of bus_driver_handle_acquire_service() and fixes - a bug where we didn't remove the service doing the acquiring + splits out part of bus_driver_handle_acquire_service() and fixes + a bug where we didn't remove the service doing the acquiring from the secondary queue if we failed to remove the current owner from the front of the queue. - + 2003-04-10 Alexander Larsson * doc/dbus-specification.sgml: s/org.freedesktop.Broadcast/org.freedesktop.DBus.Broadcast/ - + 2003-04-10 Alexander Larsson * bus/.cvsignore: * glib/.cvsignore: * test/.cvsignore: Added files to cvsignore - + * dbus/dbus-message.h: * dbus/dbus-message.c: (dbus_message_iter_get_named): Make get_named() take two out argument and return a boolean. @@ -1041,38 +1051,38 @@ * dbus/dbus-marshal.[ch]: Add array_type_pos argument to _dbus_marshal_validate_arg. Let you pass a NULL end_pos to _dbus_marshal_validate_type. - + * dbus/dbus-message.[ch]: Multi-dimensional arrays have full type specification in the outermost array. Iter code re-arranged to handle this. Added some more iter tests. - + * doc/dbus-specification.sgml: Add me to authors. Remove old FIXME. Update new array encoding description. Correct DBUS_SERVICE_FLAGS_REPLACE_EXISTING description. - + * test/data/invalid-messages/array-with-mixed-types.message: * test/data/valid-messages/array-of-array-of-uint32.message: Change to the new array format. - + * test/data/invalid-messages/too-short-dict.message: Fix bug in test. - + * test/data/valid-messages/recursive-types.message: Fix up and extend test. 2003-04-10 Havoc Pennington * bus/dispatch.c: lots of fixes - + * dbus/dbus-mainloop.c (_dbus_loop_dispatch): export (_dbus_loop_iterate): remove old "quit if no callbacks" code, that was crack, broke the test service. * dbus/dbus-transport.c (_dbus_transport_open): fix error - handling to avoid piling up errors if we get a failure on the + handling to avoid piling up errors if we get a failure on the first address. * dbus/dbus-internals.c (_dbus_real_assert_not_reached): include @@ -1113,7 +1123,7 @@ allowing us to fix up main loop usage (_dbus_connection_last_unref): free all the various function user data - (dbus_connection_dispatch): call the DispatchStatusFunction + (dbus_connection_dispatch): call the DispatchStatusFunction whenever this function returns (dbus_connection_handle_watch): call DispatchStatusFunction (dbus_connection_send_with_reply_and_block): call DispatchStatusFunction @@ -1122,7 +1132,7 @@ 2003-04-09 Havoc Pennington - * dbus/dbus-bus.c (dbus_bus_register): fix up error handling and + * dbus/dbus-bus.c (dbus_bus_register): fix up error handling and a memory leak * bus/dispatch.c (check_service_activated): fix bug in test @@ -1134,12 +1144,12 @@ e.g. in the activation case. 2003-04-08 Colin Walters - + * bus/bus.c (struct BusContext) [pidfile]: New member, to store the pid file. (bus_context_new): Set it. (bus_context_unref): Use it to delete the pid file. - + 2003-04-08 Havoc Pennington * test/data/invalid-messages/array-with-mixed-types.message: @@ -1155,7 +1165,7 @@ * test/data/valid-messages/array-of-array-of-uint32.message: happened to write this so added it to suite - + 2003-04-08 Havoc Pennington * bus/driver.c (bus_driver_handle_acquire_service): init @@ -1184,7 +1194,7 @@ * glib/test-thread-server.c: (handle_test_message): * test/test-service.c: (handle_echo): Update to new api - + * dbus/Makefile.am: * dbus/dbus-dict.c: * dbus/dbus-dict.h: @@ -1193,16 +1203,16 @@ * dbus/dbus-internals.c: (_dbus_type_to_string): Update for new types. - + * dbus/dbus-marshal.[ch]: Implement recursive types and the new marshalling format. Remove hardcoded dict marshalling. Marshal named types. - + * dbus/dbus-message-builder.c: Add BYTE_ARRAY. Remove references to old types - + * dbus/dbus-message.[ch]: New non-refcounted iter API that supports recursive iters. Use iters for appending, including support for recursive @@ -1210,24 +1220,24 @@ Add byte and named type support. Update everything to new marshalling formats. Add tests for new API. - + * dbus/dbus-protocol.h: Remove old array types. Add types: BYTE, ARRAY, DICT, NAMED - + * dbus/dbus-string.c: * dbus/dbus-sysdeps.c: Make parse_double locale safe. - + * dbus/dbus-test-main.c: Call setlocale. - + * dbus/dbus-test.c: Kill dict test - + * doc/dbus-specification.sgml: Update spec - + * test/data/incomplete-messages/missing-body.message: * test/data/invalid-messages/bad-boolean.message: * test/data/invalid-messages/bad-boolean-array.message: @@ -1242,10 +1252,10 @@ * test/data/valid-messages/recursive-types.message: Add missing NAME fields Fix up dicts & arrays - + * test/data/invalid-messages/dict-with-nil-value.message: Removed, this is not invalid anymore. - + * test/data/valid-messages/recursive-types.message: Add new test for deeply recursive types. @@ -1256,11 +1266,11 @@ 2003-04-07 Havoc Pennington - * doc/dbus-specification.sgml: require that base service names - start with ':' and that the base service is created/deleted + * doc/dbus-specification.sgml: require that base service names + start with ':' and that the base service is created/deleted as first and last things a connection does on the bus - * bus/dispatch.c (check_existent_service_activation): lots more + * bus/dispatch.c (check_existent_service_activation): lots more work on the activation test; it doesn't fully pass yet... * test/test-service.c (main): fix so we don't memleak the @@ -1269,7 +1279,7 @@ 2003-04-06 Havoc Pennington - * qt/Makefile.am (dbusinclude_HEADERS): install dbus-qt.h, + * qt/Makefile.am (dbusinclude_HEADERS): install dbus-qt.h, from Colin Walters * configure.in: fixes to Qt detection from Colin Walters @@ -1278,7 +1288,7 @@ exist, from Colin Walters * dbus/dbus-bus.c: change how we set well-known connections to - NULL, so that it works if a single connection is stored in + NULL, so that it works if a single connection is stored in two well-known array slots. * test/Makefile.am: remove a lot of stuff that isn't immediately @@ -1294,17 +1304,17 @@ elsewhere, and util functions that are used in tests/daemon but don't go in the lib. - * dbus/dbus-mainloop.h, dbus/dbus-mainloop.c: move bus/loop.[hc] + * dbus/dbus-mainloop.h, dbus/dbus-mainloop.c: move bus/loop.[hc] here so it can be used in test binaries also 2003-04-06 Havoc Pennington * dbus/dbus-sysdeps.c (_dbus_become_daemon): write the pidfile here in the parent process, so we can return an error if it - fails. Also, move some of the code into the child so the parent + fails. Also, move some of the code into the child so the parent is less hosed if we fail midway through. - * bus/bus.c (bus_context_new): move pidfile detection further up + * bus/bus.c (bus_context_new): move pidfile detection further up in the function, before we start overwriting sockets and such. * bus/messagebus.in: adjust this a bit, not sure if it will work. @@ -1326,13 +1336,13 @@ (bus_config_parser_end_element, bus_config_parser_content): Handle it. (bus_config_parser_unref): Free it. (bus_config_parser_get_pidfile): New function. - + * bus/config-parser.h (_dbus_write_pid_file): Prototype. * dbus/dbus-errors.h (DBUS_ERROR_PIDFILE_EXISTS): New error. * dbus/dbus-sysdeps.c (_dbus_write_pid_file): New function. - + * dbus/dbus-sysdeps.h: Prototype it. 2003-04-06 Havoc Pennington @@ -1340,7 +1350,7 @@ * bus/bus.c (bus_context_new): print the address in here, rather than in main(), because we need to do it before forking the daemon - * bus/dispatch.c (send_service_nonexistent_error): set the sender + * bus/dispatch.c (send_service_nonexistent_error): set the sender on the service nonexistent error * bus/driver.c (bus_driver_handle_acquire_service): set the @@ -1351,8 +1361,8 @@ 2003-04-06 Havoc Pennington - * dbus/dbus-threads.c: Redo how the fake debug mutexes are done - so it detects deadlocks and also we actually init threads when + * dbus/dbus-threads.c: Redo how the fake debug mutexes are done + so it detects deadlocks and also we actually init threads when debugging. 2003-04-06 Havoc Pennington @@ -1370,7 +1380,7 @@ 2003-04-06 Havoc Pennington * bus/bus.c (bus_context_new): fix wrong handling of - server_data_slot_unref() in the error case. + server_data_slot_unref() in the error case. * dbus/dbus-internals.h (_dbus_assert): change so it passes "(condition) != 0" to _dbus_real_assert so that @@ -1384,10 +1394,10 @@ * dbus/dbus-transport.c (_dbus_transport_open): special error for "tmpdir" option to unix: address on client side - * dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option + * dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option to unix: address - - * configure.in (TEST_SOCKET_DIR): locate a temporary directory + + * configure.in (TEST_SOCKET_DIR): locate a temporary directory we can use to create sockets in the test suite. * bus/main.c (signal_handler): on SIGTERM, exit the daemon @@ -1408,22 +1418,22 @@ 2003-04-05 Havoc Pennington - * bus/bus.c (setup_server): fix this so dbus-daemon-1 doesn't - crash on startup. Need to get "try starting the daemon" + * bus/bus.c (setup_server): fix this so dbus-daemon-1 doesn't + crash on startup. Need to get "try starting the daemon" in the test suite I guess. ;-) * dbus/dbus-server.h, dbus/dbus-server.c: remove the stuff that - tracked the number of open connections; it's better done in + tracked the number of open connections; it's better done in application-specific code as you want it to span all servers etc. 2003-04-05 Havoc Pennington - * bus/Makefile.am (install-data-hook): add missing DESTDIR, + * bus/Makefile.am (install-data-hook): add missing DESTDIR, patch from Colin Walters 2003-04-05 Havoc Pennington - * doc/config-file.txt (Elements): fix docs of to reflect + * doc/config-file.txt (Elements): fix docs of to reflect reality; in fact multiple mechanisms are allowed. * dbus/dbus-internals.c (_dbus_real_assert) @@ -1440,21 +1450,21 @@ * NEWS: update * configure.in: 0.7 - + 2003-04-05 Havoc Pennington * dbus/dbus-string.c: docs warning - + * dbus/dbus-spawn.c: missing docs * dbus/dbus-memory.c (struct ShutdownClosure): missing docs 2003-04-05 Havoc Pennington - * bus/loop.c (bus_loop_iterate): fix the timeout code, using + * bus/loop.c (bus_loop_iterate): fix the timeout code, using magic from GLib - * dbus/dbus-spawn.c (_dbus_babysitter_unref): set sitter_pid + * dbus/dbus-spawn.c (_dbus_babysitter_unref): set sitter_pid to -1 once we've reaped the babysitter (_dbus_babysitter_handle_watch): do as much work as we can, not just one go of it @@ -1475,7 +1485,7 @@ * Makefile.am (coverage-report.txt): add target "coverage-report.txt" - * test/decode-gcov.c: hack up a little program to suck data + * test/decode-gcov.c: hack up a little program to suck data out of gcov files. Yes this is sort of silly. * configure.in: define something in config.h and do an @@ -1488,15 +1498,15 @@ the spawned process and reap it when required. * test/test-segfault.c, test/test-exit.c, - test/test-sleep-forever.c: binaries that do various lame things, + test/test-sleep-forever.c: binaries that do various lame things, used in the test suite. * dbus/dbus-sysdeps.c: kill _dbus_errno_to_string() - + 2003-04-03 Havoc Pennington - * dbus/dbus-spawn.c: Move dbus-spawn into a separate file - in preparation for modifying it, dbus-sysdeps is getting + * dbus/dbus-spawn.c: Move dbus-spawn into a separate file + in preparation for modifying it, dbus-sysdeps is getting a bit unmanageable. 2003-04-03 Havoc Pennington @@ -1518,41 +1528,41 @@ 2003-04-03 Havoc Pennington - * bus/config-parser.c (bus_config_parser_unref): free + * bus/config-parser.c (bus_config_parser_unref): free list of mechanisms, bug discovered by test suite enhancements (putting system.conf and session.conf into suite) * test/Makefile.am, test/test-service.c: add placeholder for a - test service that we'll activate as part of test suite. Doesn't + test service that we'll activate as part of test suite. Doesn't do anything yet. - * dbus/dbus-sysdeps.c (_dbus_setenv): support unsetenv by - setting NULL value, and use system malloc not dbus_malloc() + * dbus/dbus-sysdeps.c (_dbus_setenv): support unsetenv by + setting NULL value, and use system malloc not dbus_malloc() when we have unavoidable memleakage. * dbus/dbus-bus.c (dbus_bus_get): fix bug where bus type of 0 didn't work, and support DBUS_BUS_ACTIVATION. - + * bus/activation.c (child_setup): pass our well-known bus type to the child * bus/config-parser.c: support to specify well-known type - * doc/dbus-specification.sgml: document the env variables to + * doc/dbus-specification.sgml: document the env variables to locate well-known buses and find service activator 2003-04-02 Havoc Pennington * test/Makefile.am (all-local): add a rule to copy tests to builddir, so we can have generated tests. Use this to remove the - silly hack for testing system.conf and session.conf. Will use this + silly hack for testing system.conf and session.conf. Will use this shortly to generate .service files pointing to test binaries. 2003-04-02 Havoc Pennington * dbus/dbus-string.c (set_length): fix a bug - we allocated max of current alloc and needed new length, not max of the doubled - allocation and needed new length. Also, when building tests, + allocation and needed new length. Also, when building tests, don't do the double-allocation stuff, just realloc every time. 2003-04-02 Havoc Pennington @@ -1599,13 +1609,13 @@ socket 0777, and unlink any existing socket. * bus/bus.c (bus_context_new): change our UID/GID and fork if - the configuration file so specifies; set up auth mechanism + the configuration file so specifies; set up auth mechanism restrictions * bus/config-parser.c (bus_config_parser_content): add support - for option and fill in code for + for option and fill in code for - * bus/system.conf.in: add to default configuration, + * bus/system.conf.in: add to default configuration, and limit auth mechanisms to EXTERNAL * doc/config-file.txt (Elements): add @@ -1615,7 +1625,7 @@ 2003-03-31 Havoc Pennington - * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket) + * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket) (_dbus_listen_unix_socket): fix off-by-one error in null termination spotted by Nalin @@ -1637,10 +1647,10 @@ 2003-03-31 Havoc Pennington Fix some annoying DBusString API and fix all affected code. - + * dbus/dbus-string.c (_dbus_string_init): get rid of annoying max_length argument - (_dbus_string_get_data): change to return string instead of using + (_dbus_string_get_data): change to return string instead of using an out param (_dbus_string_get_const_data): ditto (_dbus_string_get_data_len): ditto @@ -1653,7 +1663,7 @@ 2003-03-31 Havoc Pennington * dbus/Makefile.am (INCLUDES): use EXPANDED_LOCALSTATEDIR to - define DBUS_SYSTEM_BUS_PATH as we want to compile in the same + define DBUS_SYSTEM_BUS_PATH as we want to compile in the same final location that lands in the config file * bus/config-loader-expat.c (bus_config_load): fix type of @@ -1673,7 +1683,7 @@ * bus/main.c (main): take the configuration file as an argument. - * test/data/valid-config-files/debug-allow-all.conf: new file to + * test/data/valid-config-files/debug-allow-all.conf: new file to use with dispatch.c tests for example * bus/test-main.c (main): require test data dir @@ -1684,7 +1694,7 @@ * doc/config-file.txt (Elements): add * bus/system.conf, bus/session.conf: new files - + * dbus/dbus-bus.c (dbus_bus_get): look for system bus on well-known socket if none set @@ -1693,8 +1703,8 @@ 2003-03-30 Havoc Pennington * bus/config-parser.c: hacking - - * dbus/dbus-memory.c: don't use DBusList for the list of stuff + + * dbus/dbus-memory.c: don't use DBusList for the list of stuff to shut down, since it could cause weirdness with the DBusList lock @@ -1720,13 +1730,13 @@ * dbus/dbus-bus.c: (bus_data_free), (dbus_bus_get): * dbus/dbus-bus.h: Add dbus_bus_get. - + * dbus/dbus-memory.c: Fix a doc comment. - + 2003-03-28 Havoc Pennington - * bus/test.c (bus_test_flush_bus): remove the sleep from here, + * bus/test.c (bus_test_flush_bus): remove the sleep from here, I think it may have just been superstition. Not sure. * dbus/dbus-string.c (_dbus_string_base64_decode): catch some OOM @@ -1752,10 +1762,10 @@ * doc/TODO: Add note about automatic service activation. - + * doc/dbus-specification.sgml: Rename the specification and clarify a few things. - + 2003-03-26 Anders Carlsson * Doxyfile.in: @@ -1765,7 +1775,7 @@ * dbus/dbus-server-debug-pipe.c: * dbus/dbus-transport-unix.c: Fix documentation warnings. - + 2003-03-26 Havoc Pennington * bus/test-main.c, dbus/dbus-test.c (main): check memleaks @@ -1784,11 +1794,11 @@ 2003-03-25 Havoc Pennington * throughout - add more _DBUS_ASSERT_ERROR_IS_CLEAR - + * configure.in: add --with-xml option to specify XML library, right now only libxml is supported. - * bus/config-loader-libxml.c, config-parser.c: sync some minor + * bus/config-loader-libxml.c, config-parser.c: sync some minor nonworking code between home and work, still just stubs 2003-03-24 Havoc Pennington @@ -1796,8 +1806,8 @@ * dbus/dbus-sysdeps.c (_dbus_set_fd_nonblocking): move to this file - * dbus/dbus-errors.c (dbus_set_error, dbus_set_error_const): allow - NULL argument for "message" if the error is a well-known one, + * dbus/dbus-errors.c (dbus_set_error, dbus_set_error_const): allow + NULL argument for "message" if the error is a well-known one, fill in a generic message in this case. * dbus/dbus-errors.h (DBusResultCode): Kill DBusResultCode in @@ -1809,20 +1819,20 @@ 2003-03-24 Havoc Pennington - * bus/connection.c (bus_connections_setup_connection): set up - the "can this user connect" function, but it always returns + * bus/connection.c (bus_connections_setup_connection): set up + the "can this user connect" function, but it always returns TRUE until we have a config file parser so we can have a config file that allows connections. 2003-03-23 Havoc Pennington - * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with - DBUS_BUILD_TESTS, actually alloc/free a block of memory for - the mutex, so we can check for proper memory management + * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with + DBUS_BUILD_TESTS, actually alloc/free a block of memory for + the mutex, so we can check for proper memory management and OOM handling. * dbus/dbus-dataslot.c: remove the mutex from - DBusDataSlotAllocator and lock it manually when using it, + DBusDataSlotAllocator and lock it manually when using it, to simplify fitting it into the global slots framework. * dbus/dbus-threads.c (init_static_locks): rework how we're @@ -1832,17 +1842,17 @@ * bus/test-main.c (main): check for memleaks - * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make + * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make test suite check for memleaks - * dbus/dbus-memory.c: add support in test mode for tracking + * dbus/dbus-memory.c: add support in test mode for tracking number of outstanding blocks 2003-03-23 Havoc Pennington * bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny policies code - + * dbus/dbus-hash.h: add ULONG hash keys * dbus/dbus-sysdeps.c (_dbus_get_groups): new @@ -1869,7 +1879,7 @@ 2003-03-19 Havoc Pennington - * bus/policy.c: start sketching code for policy restrictions on + * bus/policy.c: start sketching code for policy restrictions on what connections can do. 2003-03-18 Havoc Pennington @@ -1884,14 +1894,14 @@ * configure.in: 0.6 * NEWS: Update. - + 2003-03-17 Havoc Pennington - * dbus/dbus-internals.h: add gcc attributes so that - our printf-style functions warn on bad arguments to + * dbus/dbus-internals.h: add gcc attributes so that + our printf-style functions warn on bad arguments to format - - * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix printf + + * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix printf format bug * dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix @@ -1899,10 +1909,10 @@ 2003-03-17 Havoc Pennington - * bus/test-main.c (main): make it print something as it runs + * bus/test-main.c (main): make it print something as it runs so make check doesn't look stuck - * doc/negotiation.txt, doc/dbus-sasl-profile.txt: remove + * doc/negotiation.txt, doc/dbus-sasl-profile.txt: remove from CVS, now obsolete 2003-03-17 Anders Carlsson @@ -1910,15 +1920,15 @@ * bus/dispatch.c: (bus_dispatch): Refetch the service name since it may have been reallocated when dbus_message_set_sender was called. - + * dbus/dbus-sysdeps.c: (_dbus_accept): Add address and address length variables and use them to stop valgrind from complaining. - + 2003-03-17 Havoc Pennington All tests pass, no memleaks, no valgrind complaints. - + * bus/test.c: refcount handler_slot * bus/connection.c (bus_connections_new): refcount @@ -1965,22 +1975,22 @@ * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): add some missing dbus_set_result - * bus/dispatch.c (bus_dispatch_add_connection): handle failure to + * bus/dispatch.c (bus_dispatch_add_connection): handle failure to alloc the DBusMessageHandler * dbus/dbus-transport.c (_dbus_transport_disconnect): don't ref - the transport here, since we call this from the finalizer; it + the transport here, since we call this from the finalizer; it resulted in a double-finalize. - * dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug - where we tried to use transport->connection that was NULL, + * dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug + where we tried to use transport->connection that was NULL, happened when transport was disconnected early on due to OOM * bus/*.c: adapt to handle OOM for watches/timeouts - * dbus/dbus-transport-unix.c: port to handle OOM during + * dbus/dbus-transport-unix.c: port to handle OOM during watch handling - + * dbus/dbus-auth.c (_dbus_auth_get_unused_bytes): return a reference to unused bytes instead of a copy @@ -1997,7 +2007,7 @@ * doc/dbus-specification.sgml: Document reply message for ActivateService. - + 2003-03-16 Anders Carlsson * bus/activation.c: (bus_pending_activation_entry_free), @@ -2017,7 +2027,7 @@ * dbus/dbus-protocol.h: Make activation work better. Now pending activations will be queued and the daemon won't try to activate services that are already registered. - + 2003-03-16 Havoc Pennington * dbus/dbus-bus.c (ensure_bus_data): handle failure to set @@ -2033,8 +2043,8 @@ * bus/*: adapt to DBusConnection API changes - * glib/dbus-gmain.c: adapt to DBusConnection API changes, - requires renaming stuff to avoid dbus_connection_dispatch name + * glib/dbus-gmain.c: adapt to DBusConnection API changes, + requires renaming stuff to avoid dbus_connection_dispatch name conflict. * dbus/dbus-transport.c (_dbus_transport_queue_messages): new @@ -2060,7 +2070,7 @@ * dbus/dbus-connection.c: (dbus_connection_send_with_reply_and_block): - Decrease connection->n_incoming when removing an entry + Decrease connection->n_incoming when removing an entry from the list. * dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_set_boolean_array), (dbus_dict_set_int32_array), @@ -2069,7 +2079,7 @@ (dbus_dict_get_boolean_array), (dbus_dict_get_double_array), (dbus_dict_get_byte_array): Handle NULL arrays and strings. Also add support for byte arrays. - + * dbus/dbus-marshal.c: (_dbus_marshal_byte_array), (_dbus_marshal_dict), (_dbus_demarshal_byte_array), (_dbus_demarshal_int32_array), (_dbus_demarshal_uint32_array), @@ -2078,7 +2088,7 @@ (_dbus_marshal_validate_arg), (_dbus_marshal_test): * dbus/dbus-marshal.h: Add support for marshalling and demarshalling empty arrays and strings. - + * dbus/dbus-message.c: (dbus_message_append_args_valist), (dbus_message_append_string_array), (dbus_message_iter_get_boolean), @@ -2090,14 +2100,14 @@ (dbus_message_iter_get_string_array), (dbus_message_iter_get_dict), (check_message_handling): Add support for getting empty arrays and dicts. - + * dbus/dbus-string.c: (_dbus_string_validate_utf8): Don't do any validation at all for now, that's better than just checking for ASCII. - + * test/data/valid-messages/emptiness.message: New test message with lots of empty arrays. - + 2003-03-16 Havoc Pennington * dbus/dbus-connection.c @@ -2105,7 +2115,7 @@ can't fail due to OOM * dbus/dbus-message.c (_dbus_message_loader_pop_message_link): - new function pops a message together with a list link + new function pops a message together with a list link containing it. * dbus/dbus-transport-unix.c (queue_messages): use new link-based @@ -2120,20 +2130,20 @@ in the shared lib, and only daemon mallocs were tested. In any case, the test case now tests all 500+ mallocs, and doesn't pass yet, though there are lots of fixes in this patch. - + * dbus/dbus-connection.c (dbus_connection_dispatch_message): fix - this so that it doesn't need to allocate memory, since it - has no way of indicating failure due to OOM (and would be + this so that it doesn't need to allocate memory, since it + has no way of indicating failure due to OOM (and would be annoying if it did). * dbus/dbus-list.c (_dbus_list_pop_first_link): new function * bus/Makefile.am: rearrange to create two self-contained - libraries, to avoid having libraries with overlapping symbols. - that was resulting in weirdness, e.g. I'm pretty sure there + libraries, to avoid having libraries with overlapping symbols. + that was resulting in weirdness, e.g. I'm pretty sure there were two copies of global static variables. - * dbus/dbus-internals.c: move the malloc debug stuff to + * dbus/dbus-internals.c: move the malloc debug stuff to dbus-memory.c * dbus/dbus-list.c (free_link): free list mempool if it becomes @@ -2145,15 +2155,15 @@ on failure. * bus/dispatch.c (bus_dispatch_add_connection): free - message_handler_slot when no longer using it, so + message_handler_slot when no longer using it, so memory leak checkers are happy for the test suite. * dbus/dbus-server-debug-pipe.c (debug_finalize): free server name - * bus/bus.c (new_connection_callback): disconnect in here if + * bus/bus.c (new_connection_callback): disconnect in here if bus_connections_setup_connection fails. - * bus/connection.c (bus_connections_unref): fix to free the + * bus/connection.c (bus_connections_unref): fix to free the connections (bus_connections_setup_connection): if this fails, don't disconnect the connection, just be sure there are no side @@ -2163,11 +2173,11 @@ * dbus/dbus-auth.c (_dbus_auth_unref): free some stuff we were leaking - (_dbus_auth_new): fix the order in which we free strings + (_dbus_auth_new): fix the order in which we free strings on OOM failure - * bus/connection.c (bus_connection_disconnected): fix to - not send ServiceDeleted multiple times in case of memory + * bus/connection.c (bus_connection_disconnected): fix to + not send ServiceDeleted multiple times in case of memory allocation failure * dbus/dbus-bus.c (dbus_bus_get_base_service): new function to @@ -2177,18 +2187,18 @@ function for it. (dbus_bus_register_client): rename dbus_bus_register() - * bus/dispatch.c (check_hello_message): verify that other - connections on the bus also got the correct results, not + * bus/dispatch.c (check_hello_message): verify that other + connections on the bus also got the correct results, not just the one sending hello 2003-03-15 Havoc Pennington Make it pass the Hello handling test including all OOM codepaths. Now to do other messages... - + * bus/services.c (bus_service_remove_owner): fix crash when removing owner from an empty list of owners - (bus_registry_ensure): don't leave service in the list of + (bus_registry_ensure): don't leave service in the list of a connection's owned services if we fail to put the service in the hash table. @@ -2203,7 +2213,7 @@ needed. (unix_connection_set): this can now fail on OOM - * dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept + * dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept of enabling/disabling a watch or timeout. * bus/loop.c (bus_loop_iterate): don't touch disabled @@ -2222,69 +2232,69 @@ watch). To fix this, I think we need to add new stuff to set_watch_functions, namely a SetEnabled function so we can alloc the watch earlier, then enable it later. - + * dbus/Makefile.am (libdbus_convenience_la_SOURCES): move dbus-memory.c to the convenience lib - * bus/test.c: rename some static functions to keep them clearly + * bus/test.c: rename some static functions to keep them clearly distinct from stuff in connection.c. Handle client disconnection. 2003-03-14 Havoc Pennington - * bus/dispatch.c (bus_dispatch_test): do test using debug-pipe - transport, tests more of the real codepath. Set up clients + * bus/dispatch.c (bus_dispatch_test): do test using debug-pipe + transport, tests more of the real codepath. Set up clients with bus_setup_debug_client. - * bus/test.c (bus_setup_debug_client): function to set up debug + * bus/test.c (bus_setup_debug_client): function to set up debug "clients" on the main loop - * dbus/dbus-transport.c (_dbus_transport_open): add debug-pipe + * dbus/dbus-transport.c (_dbus_transport_open): add debug-pipe support - * dbus/dbus-server.c (dbus_server_listen): add debug-pipe + * dbus/dbus-server.c (dbus_server_listen): add debug-pipe server type * dbus/dbus-server-debug.c: support a debug server based on pipes * dbus/dbus-sysdeps.c (_dbus_full_duplex_pipe): new function (_dbus_close): new function - + * configure.in: check for socketpair 2003-03-14 Havoc Pennington - * dbus/dbus-memory.c: add a "detect buffer overwrites on free" + * dbus/dbus-memory.c: add a "detect buffer overwrites on free" cheesy hack - * dbus/dbus-transport-debug.c: rework this a good bit to be + * dbus/dbus-transport-debug.c: rework this a good bit to be less complicated. hopefully still works. * dbus/dbus-server-debug.c (handle_new_client): remove timeout manually - * glib/dbus-gmain.c (timeout_handler): don't remove timeout + * glib/dbus-gmain.c (timeout_handler): don't remove timeout after running it - * dbus/dbus-message.c (dbus_message_copy): rename from - dbus_message_new_from_message, fix it up to copy + * dbus/dbus-message.c (dbus_message_copy): rename from + dbus_message_new_from_message, fix it up to copy all the message fields, add test case - * bus/dispatch.c (bus_dispatch_test): add some more test code, + * bus/dispatch.c (bus_dispatch_test): add some more test code, not quite passing yet 2003-03-14 Havoc Pennington * bus/loop.c (bus_loop_iterate): add this so we can "run loop - until no work remains" in test code. (the large diff here + until no work remains" in test code. (the large diff here is just code movement, no actual changes) * dbus/dbus-server-debug.c (DEFAULT_INTERVAL): change interval to 1, no point waiting around for test code. - (_dbus_server_debug_accept_transport): unref the timeout + (_dbus_server_debug_accept_transport): unref the timeout after adding it (right?) * dbus/dbus-transport-debug.c (DEFAULT_INTERVAL): ditto - + 2003-03-13 Havoc Pennington * dbus/dbus-timeout.c (_dbus_timeout_list_set_functions): handle @@ -2312,33 +2322,33 @@ * bus/dispatch.c (bus_dispatch_test): started adding this but didn't finish - + 2003-03-14 Anders Carlsson * bus/dispatch.c (send_service_nonexistent_error): Fix typo. 2003-03-13 Havoc Pennington - * bus/test.c, bus/test.h, bus/Makefile.am, bus/test-main.c: + * bus/test.c, bus/test.h, bus/Makefile.am, bus/test-main.c: set up a test framework as for the library 2003-03-12 Havoc Pennington - Throughout: purge global variables, introduce BusActivation, + Throughout: purge global variables, introduce BusActivation, BusConnections, BusRegistry, etc. objects instead. - - * bus/bus.h, bus/bus.c: introduce BusContext as a global + + * bus/bus.h, bus/bus.c: introduce BusContext as a global message bus object - * test/Makefile.am (TEST_BINARIES): disable bus-test for now, + * test/Makefile.am (TEST_BINARIES): disable bus-test for now, going to redo this a bit differently I think - + 2003-03-12 Havoc Pennington - Mega-patch that gets the message bus daemon initially handling - out-of-memory. Work still needed. Also lots of random + Mega-patch that gets the message bus daemon initially handling + out-of-memory. Work still needed. Also lots of random moving stuff to DBusError instead of ResultCode. - + * dbus/dbus-list.c (_dbus_list_length_is_one): new function * dbus/dbus-connection.c @@ -2354,7 +2364,7 @@ rename bus_connection_disconnected as it's a notification only * bus/driver.c (bus_driver_handle_acquire_service): don't free - "name" on get_args failure, should be done by get_args; + "name" on get_args failure, should be done by get_args; don't disconnect client for bad args, just return an error. (bus_driver_handle_service_exists): ditto @@ -2376,8 +2386,8 @@ * bus/connection.c (bus_connection_foreach): allow stopping iteration by returning FALSE from foreach function. - * dbus/dbus-connection.c (dbus_connection_send_preallocated) - (dbus_connection_free_preallocated_send) + * dbus/dbus-connection.c (dbus_connection_send_preallocated) + (dbus_connection_free_preallocated_send) (dbus_connection_preallocate_send): new API for sending a message without possibility of malloc failure. (dbus_connection_send_message): rename to just @@ -2397,23 +2407,23 @@ 2003-03-10 Anders Carlsson - * dbus/dbus-marshal.c: + * dbus/dbus-marshal.c: (_dbus_marshal_set_string): Take a length argument so we can marshal the correct string length. - + (_dbus_marshal_dict), (_dbus_demarshal_dict), (_dbus_marshal_get_arg_end_pos), (_dbus_marshal_validate_arg), (_dbus_marshal_test): - * dbus/dbus-marshal.h: + * dbus/dbus-marshal.h: Add support for marshalling and demarshalling dicts. - + * dbus/dbus-message-builder.c: (_dbus_message_data_load): Add support for TYPE DICT. - + * dbus/dbus-message.c: (set_string_field): Adjust header padding. - + (dbus_message_append_args_valist), (dbus_message_append_dict), (dbus_message_get_args_valist), (dbus_message_iter_get_arg_type), (dbus_message_iter_get_dict), (_dbus_message_loader_return_buffer), @@ -2423,13 +2433,13 @@ * dbus/dbus-protocol.h: Add DBUS_TYPE_DICT. - + * dbus/dbus.h: Add dbus-dict.h - + * doc/dbus-specification.sgml: Add information about how dicts are marshalled. - + * test/data/invalid-messages/dict-with-nil-value.message: * test/data/invalid-messages/too-short-dict.message: * test/data/valid-messages/dict-simple.message: @@ -2452,7 +2462,7 @@ (dbus_dict_set_string_array), (_dbus_dict_test): * dbus/dbus-dict.h: Fix according to comments from Havoc. - + 2003-03-06 Michael Meeks * configure.in: if we don't have kde-config, disable have_qt. @@ -2461,7 +2471,7 @@ * dbus/Makefile.am: Add dbus-dict.[ch] - + * dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_new), (dbus_dict_ref), (dbus_dict_unref), (dbus_dict_contains), (dbus_dict_remove), (dbus_dict_get_value_type), @@ -2478,11 +2488,11 @@ (dbus_dict_get_string_array), (_dbus_dict_test): * dbus/dbus-dict.h: Add DBusDict implementation - + * dbus/dbus-test.c: (dbus_internal_do_not_use_run_tests): * dbus/dbus-test.h: Add _dbus_dict_test - + 2003-03-04 Havoc Pennington * test/data/auth/*: adapt to changes @@ -2492,15 +2502,15 @@ userid * dbus/dbus-keyring.c (_dbus_keyring_validate_context): prevent - more stuff from being in a context name, to make the protocol + more stuff from being in a context name, to make the protocol simpler to deal with * dbus/dbus-errors.c (dbus_error_has_name): new function (dbus_error_is_set): new function - * dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth + * dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth with DBUS_COOKIE_SHA1, implement DBUS_COOKIE_SHA1 - + * dbus/dbus-connection.c (dbus_connection_flush): also read messages during a flush operation @@ -2512,10 +2522,10 @@ * dbus/dbus-transport.c: (_dbus_transport_open): Remove duplicate "tcp" entry. - + * doc/dbus-specification.sgml: Clarify some things. - + 2003-03-05 Anders Carlsson * dbus/dbus-auth.c: (send_rejected), (process_test_subdir): @@ -2540,7 +2550,7 @@ sets really huge and small integers * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): add check - that length of boolean array fits in the string, and that + that length of boolean array fits in the string, and that string has room for boolean value in single-bool case. * dbus/dbus-message-builder.c (_dbus_message_data_load): add @@ -2574,7 +2584,7 @@ 2003-02-27 Alexander Larsson - * glib/Makefile.am: + * glib/Makefile.am: * configure.in: Make gthreads-2.0 dependency optional. Don't build thread test if its not found. @@ -2585,14 +2595,14 @@ (dbus_connection_send_message_with_reply_and_block): fix doh! doh! doh! bug that resulted in never removing a reply from the queue, no wonder we called get_reply_serial so much ;-) - + * dbus/dbus-message.c (struct DBusMessage): cache reply serial and client serial instead of demarshaling them every time 2003-02-27 Havoc Pennington * dbus/dbus-marshal.c (_dbus_demarshal_int32): rewrite to be much - more inlined, using dbus-string-private.h, speeds things up + more inlined, using dbus-string-private.h, speeds things up substantially * dbus/dbus-string.c (_dbus_string_free): apply align offset @@ -2602,17 +2612,17 @@ 2003-02-26 Havoc Pennington - All kinds of audit fixes from Owen, plus initial attempt to + All kinds of audit fixes from Owen, plus initial attempt to handle unaligned memory returned from malloc. - - * dbus/dbus-string.c (_dbus_string_init): clamp max length to + + * dbus/dbus-string.c (_dbus_string_init): clamp max length to leave room for align_offset and nul byte - (fixup_alignment): function to track an align_offset and + (fixup_alignment): function to track an align_offset and ensure real->str is aligned - (DBUS_GENERIC_STRING_PREAMBLE): len must be less than allocated, + (DBUS_GENERIC_STRING_PREAMBLE): len must be less than allocated, to allow a nul byte plus align offset (_dbus_string_lock): fix overflow issue - (_dbus_string_init_const_len): add assertions on sanity of len, + (_dbus_string_init_const_len): add assertions on sanity of len, assign allocated to be ALLOCATION_PADDING larger than len (set_length): fixup the overflow handling (_dbus_string_get_data_len): fix overflow in assertion @@ -2624,16 +2634,16 @@ (_dbus_string_delete): fix overflow in assertion (_dbus_string_copy_len): overflow in assertion (_dbus_string_replace_len): overflows in assertions - (_dbus_string_find): change to implement in terms of + (_dbus_string_find): change to implement in terms of _dbus_string_find_to (_dbus_string_find_to): assorted fixage - (_dbus_string_equal_c_str): assert c_str != NULL, + (_dbus_string_equal_c_str): assert c_str != NULL, fix logic so the function works (_dbus_string_ends_with_c_str): fix overflow thingy (_dbus_string_base64_encode): overflow fix (_dbus_string_validate_ascii): overflow (_dbus_string_validate_nul): overflow - + 2003-02-26 Havoc Pennington * dbus/dbus-marshal.c (_dbus_marshal_test): fix to work with DISABLE_ASSERTS @@ -2642,29 +2652,29 @@ * configure.in: Set DBUS_GLIB_THREADS_LIBS for apps using gthread-2.0 - + * dbus/dbus-connection.c: * dbus/dbus-connection.h: Fix _dbus_connection_acquire_io_path and _dbus_connection_acquire_dispatch. Add dbus_connection_set_wakeup_main_function and use it when queueing incoming and outgoing messages. - - + + * dbus/dbus-dataslot.c: Threadsafe usage of DBusDataSlotAllocator - + * dbus/dbus-message.c: (dbus_message_get_args_iter): dbus_new can fail. - + * dbus/dbus-server-unix.c: Add todo comment - + * glib/dbus-gmain.c: Implement the new wakeup functions for glib. - + * glib/Makefile.am: - * glib/test-thread-client.c: - * glib/test-thread-server.c: + * glib/test-thread-client.c: + * glib/test-thread-server.c: * glib/test-thread.h: Initial cut at some thread test code. Not really done yet. @@ -2678,7 +2688,7 @@ at the end of this function, so if we didn't need to read for authentication, we reinstall it for receiving messages - * dbus/dbus-message.c (dbus_message_new_reply): allow replies to + * dbus/dbus-message.c (dbus_message_new_reply): allow replies to a NULL sender for peer-to-peer case * dbus/dbus-transport-unix.c (check_read_watch): handle @@ -2696,9 +2706,9 @@ * Doxyfile.in (INPUT): add glib subdir - * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename + * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename setup_with_g_main instead of hookup_with_g_main; write docs - + 2003-02-24 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_validate_arg): @@ -2709,11 +2719,11 @@ * dbus/dbus-message.h: * doc/dbus-specification.sgml: Various fixes as pointed out by Havoc. - + * test/data/invalid-messages/bad-boolean-array.message: * test/data/invalid-messages/bad-boolean.message: Add invalid boolean value test cases. - + 2003-02-24 Anders Carlsson * dbus/dbus-internals.c: (_dbus_type_to_string): @@ -2731,10 +2741,10 @@ * doc/dbus-specification.sgml: * test/data/valid-messages/lots-of-arguments.message: Add support for boolean and boolean array types. - + 2003-02-23 Havoc Pennington - * dbus/dbus-keyring.c: finish most of this implementation and + * dbus/dbus-keyring.c: finish most of this implementation and simple unit test * dbus/dbus-errors.c (dbus_set_error_const, dbus_set_error): make @@ -2753,7 +2763,7 @@ * dbus/dbus-md5.c (_dbus_md5_compute): use dbus_string_hex_encode - * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): make this use + * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): make this use the save-to-temp/rename trick to atomically write the new file (_dbus_string_parse_uint): new function @@ -2774,25 +2784,25 @@ * dbus/dbus-marshal.c: (_dbus_demarshal_string_array): Make string arrays NULL-terminated. - + * dbus/dbus-memory.c: (dbus_free_string_array): * dbus/dbus-memory.h: New function for freeing NULL-terminated string arrays. - + * dbus/dbus-message-builder.c: (append_quoted_string), (_dbus_message_data_load): Add support for array types. - + * dbus/dbus-message.c: (check_message_handling): Add more types as test cases. - + * dbus/dbus-sysdeps.c: (_dbus_string_parse_int), (_dbus_string_parse_double): Add the start offset to the end offset. - + * test/data/valid-messages/lots-of-arguments.message: New test message with lots of arguments. - + 2003-02-21 Anders Carlsson * dbus/dbus-message.c: (dbus_message_append_nil), @@ -2809,7 +2819,7 @@ * dbus/dbus-message.c: (dbus_message_append_nil): Fix a silly. - + 2003-02-21 Anders Carlsson * dbus/dbus-message.c: (dbus_message_append_args_valist), @@ -2826,7 +2836,7 @@ * dbus/dbus-message.h: Add functions for appending and getting arrays. - + 2003-02-21 Anders Carlsson * dbus/dbus-mempool.c (_dbus_mem_pool_new): Make the @@ -2839,7 +2849,7 @@ Unlock the connection mutex during a blocking select call. Add todo about how we need a way to wake up the select. - * dbus/dbus-connection-internal.h: + * dbus/dbus-connection-internal.h: * dbus/dbus-connection.c: Add _dbus_connection_lock and _dbus_connection_unlock. @@ -2855,7 +2865,7 @@ * dbus/dbus-errors.c (dbus_set_error_const): do not call dbus_error_init (dbus_set_error): remove dbus_error_init, check for message == - NULL *before* we sprintf into it, and add @todo about including + NULL *before* we sprintf into it, and add @todo about including system headers in this file * dbus/dbus-sysdeps.c (_dbus_create_file_exclusively): new @@ -2863,7 +2873,7 @@ * dbus/dbus-errors.h (DBUS_ERROR_FAILED): add * dbus/dbus-sysdeps.c (get_user_info): break this function out to - get various bits of user information based on either username + get various bits of user information based on either username or user ID (_dbus_homedir_from_username): new function @@ -2871,22 +2881,22 @@ * configure.in: Add check for nonposix getpwnam_r - + * dbus/dbus-mempool.c: (_dbus_mem_pool_new): Align the pool element size to a sizeof (void *) boundary. - + * dbus/dbus-sysdeps.c: (_dbus_setenv), (_dbus_connect_unix_socket), (_dbus_listen_unix_socket), (_dbus_credentials_from_username): General Solaris fixes. - + * test/data/valid-messages/simplest-manual.message: Explicitly state that we want little-endian packing. - + 2003-02-19 Mikael Hallendal * dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses. - * dbus/dbus-transport-unix.c (_dbus_transport_new_for_tcp_socket): + * dbus/dbus-transport-unix.c (_dbus_transport_new_for_tcp_socket): Added to create a transport connecting using a tcp/ip socket. * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): Added to connect @@ -2896,14 +2906,14 @@ * dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses. - * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket): + * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket): Added to create a server listening on a TCP/IP socket. 2003-02-19 Havoc Pennington Throughout: mop up all the Doxygen warnings and undocumented stuff. - + * dbus/dbus-sysdeps.c (do_exec): do not use execvp, we don't want to search any paths. @@ -2912,10 +2922,10 @@ besides being kind of ugly * Doxyfile (PREDEFINED): have Doxygen define - DOXYGEN_SHOULD_SKIP_THIS so we can exclude things from + DOXYGEN_SHOULD_SKIP_THIS so we can exclude things from docs with #ifndef DOXYGEN_SHOULD_SKIP_THIS - (do not abuse the feature! it's for stuff like the autogenerated - macros in dbus-md5.c, not just for things you don't feel like + (do not abuse the feature! it's for stuff like the autogenerated + macros in dbus-md5.c, not just for things you don't feel like documenting...) 2003-02-18 Havoc Pennington @@ -2964,14 +2974,14 @@ 2003-02-17 Anders Carlsson Release 0.4 - + * NEWS: Update 2003-02-17 Anders Carlsson * doc/dbus-specification.sgml: Specification updates. - + 2003-02-17 Anders Carlsson * bus/activation.c: (bus_activation_init), (child_setup), @@ -2979,21 +2989,21 @@ * bus/activation.h: * bus/main.c: (main): Set DBUS_ADDRESS environment variable. - + * dbus/dbus-errors.c: (dbus_set_error): Don't use va_copy since that's a C99 feature. - + * dbus/dbus-sysdeps.c: (_dbus_setenv), (do_exec), (_dbus_spawn_async): * dbus/dbus-sysdeps.h: Add child_setup_func to _dbus_spawn_async. - + * doc/dbus-specification.sgml: Update specification. - + * test/spawn-test.c: (setup_func), (main): Fix test. - + 2003-02-17 Alexander Larsson * dbus/dbus-connection.c (_dbus_connection_handler_destroyed_locked): @@ -3005,10 +3015,10 @@ * doc/Makefile.am: * doc/dbus-test-plan.sgml: Add test plan document. - + * test/Makefile.am: Fix distcheck. - + 2003-02-17 Anders Carlsson * dbus/dbus-message.c: (decode_header_data), @@ -3019,11 +3029,11 @@ * bus/dispatch.c: (send_one_message): Only send broadcast messages to registered connections. - + * dbus/dbus-message.c: (dbus_message_name_is): * dbus/dbus-message.h: New convenience function. - + * dbus/dbus-transport-debug.c: (do_reading): Only dispatch one message per run. @@ -3034,7 +3044,7 @@ * test/bus-test-loop.[ch]: Add these. - + 2003-02-16 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_dispatch_message): fix @@ -3046,7 +3056,7 @@ Implement sent_message_with_reply. (with_reply_and block is still busted). Made dispatch_message not lose message if OOM. - + * dbus/dbus-errors.h: Add NoReply error (for reply timeouts). @@ -3059,51 +3069,51 @@ * dbus/dbus-auth.c: (client_try_next_mechanism): Plug a leak. - + * dbus/dbus-threads.c: (dbus_condvar_wait_timeout): Return TRUE if there's no thread implementation around. - + * glib/dbus-gmain.c: (free_source), (dbus_connection_hookup_with_g_main): Make sure to remove the GSource when the connection is finalized. - + 2003-02-16 Anders Carlsson * bus/dispatch.c: (bus_dispatch_message_handler): * dbus/dbus-errors.h: Return an error if someone tries to send a message to a service that doesn't exist. - + 2003-02-16 Anders Carlsson * bus/activation.c: (load_directory), (bus_activation_init), (bus_activation_activate_service): * bus/activation.h: - * bus/driver.c: + * bus/driver.c: (bus_driver_handle_activate_service), (bus_driver_handle_message): More work on the activation handling. - + * dbus/dbus-errors.h: Add some error messages - + * dbus/dbus-message.c: (dbus_message_new_error_reply): * dbus/dbus-message.h: New function that creates an error message. - + * dbus/dbus-protocol.h: Add ACTIVATE_SERVER message. - + * dbus/dbus-server-unix.c: (unix_handle_watch), (_dbus_server_new_for_domain_socket): Call _dbus_fd_set_close_on_exec. - + * dbus/dbus-sysdeps.c: (make_pipe), (do_exec), (_dbus_spawn_async), (_dbus_disable_sigpipe), (_dbus_fd_set_close_on_exec): * dbus/dbus-sysdeps.h: Add _dbus_fd_set_close_on exec function. Also add function that checks that all open fds are set to close-on-exec and warns otherwise. - + * dbus/dbus-transport-unix.c: (_dbus_transport_new_for_domain_socket): Call _dbus_fd_set_close_on_exec. @@ -3112,7 +3122,7 @@ * dbus/dbus-connection.c (dbus_connection_set_change_sigpipe): allow people to avoid setting SIGPIPE to SIG_IGN - (_dbus_connection_new_for_transport): disable SIGPIPE unless + (_dbus_connection_new_for_transport): disable SIGPIPE unless we've been asked not to 2003-02-15 Anders Carlsson @@ -3141,24 +3151,24 @@ * dbus/dbus-errors.c: (dbus_set_error): * dbus/dbus-errors.h: Add a few errors and make dbus_set_error void. - - * dbus/dbus-sysdeps.c: + + * dbus/dbus-sysdeps.c: (_dbus_errno_to_string), (close_and_invalidate), (make_pipe), (write_err_and_exit), (read_ints), (do_exec), (_dbus_spawn_async): * dbus/dbus-sysdeps.h: Add _dbus_spawn_async. - + * test/spawn-test.c: (main): Test for _dbus_spawn_async. - + 2003-02-15 Anders Carlsson * dbus/dbus-internals.h: Fix build without tests. - + * dbus/dbus-list.c: (alloc_link): Fix a segfault when a malloc fails. - + * dbus/dbus-memory.c: (initialize_malloc_debug), (dbus_malloc), (dbus_malloc0), (dbus_realloc): Add support for malloc debugging. @@ -3169,12 +3179,12 @@ * dbus/dbus-threads.h: Add condvars. Remove static mutext from API. Implement static mutexes by initializing them from threads_init. - + * glib/dbus-gthread.c: * qt/dbus-qthread.cpp: Update with the thread api changes. - + * dbus/dbus-list.c: * dbus/dbus-list.h: Turn StaticMutex into normal mutex + init function. @@ -3182,18 +3192,18 @@ _dbus_list_append_link, _dbus_list_prepend_link - * dbus/dbus-sysdeps.c: + * dbus/dbus-sysdeps.c: * dbus/dbus-sysdeps.h: New type dbus_atomic_t, and new functions _dbus_atomic_inc, _dbus_atomic_dec. Only slow fallback implementation at the moment. - + * dbus/dbus-protocol.h: Add DBUS_MESSAGE_LOCAL_DISCONNECT define - + * dbus/dbus-message.c: Make ref/unref atomic. Fix some docs. - + * dbus/dbus-connection-internal.h: * dbus/dbus-connection.c: * dbus/dbus-connection.h: @@ -3201,23 +3211,23 @@ Change _peek to _borrow,_return & _steal_borrowed. Change disconnect callback to event. Make dbus_connection_dispatch_messages reentrant. - + * dbus/dbus-transport.c: Don't ref the connection on calls to the transport implementation. - + * dbus/dbus-message-handler.c: Make threadsafe. - + * glib/dbus-gmain.c: Don't use peek_message anymore - + * test/Makefile.am: * test/debug-thread.c: * test/debug-thread.h: Simple thread implementation that asserts() on deadlocks in single-threaded code. - + * test/bus-test.c: (main) Call debug_threads_init. @@ -3228,10 +3238,10 @@ * bus/connection.h: Don't call dbus_connection_set_disconnect_function. Instead export bus_connection_disconnect. - + * bus/dispatch.c: Call bus_connection_disconnect when we get a disconnected message. - + 2003-02-15 Havoc Pennington * dbus/dbus-message.c (dbus_message_new): fool around with the @@ -3245,12 +3255,12 @@ should * dbus/dbus-internals.c (_dbus_set_fail_alloc_counter) - (_dbus_decrement_fail_alloc_counter): debug functions to + (_dbus_decrement_fail_alloc_counter): debug functions to simulate memory allocation failures 2003-02-14 Havoc Pennington - * dbus/dbus-errors.h (struct DBusError): add a word of padding + * dbus/dbus-errors.h (struct DBusError): add a word of padding to DBusError 2003-02-13 Anders Carlsson @@ -3259,10 +3269,10 @@ * bus/driver.h: * bus/services.c: (bus_service_lookup): Reorder message sending so we get a more sane order. - + * test/bus-test.c: (message_handler): Fix tyop. - + 2003-02-13 Anders Carlsson * bus/driver.c: (bus_driver_send_service_deleted), @@ -3287,10 +3297,10 @@ * test/bus-test.c: (main): Change fields to arguments in messages, so that they won't be confused with header fields. - + * glib/test-dbus-glib.c: (main): Remove append_fields from hello message. - + 2003-02-13 Anders Carlsson * dbus/dbus-errors.c: @@ -3303,36 +3313,36 @@ * glib/dbus-gmain.c: (timeout_handler), (add_timeout), (remove_timeout): Implement support for timeouts in dbus-glib. - + 2003-02-13 Anders Carlsson * dbus/dbus-message-builder.c: (_dbus_message_data_load): * dbus/dbus-message.c: (process_test_subdir): * test/break-loader.c: (find_breaks_based_on): Plug some memory leaks. - + 2003-02-13 Richard Hult * bus/main.c: Fix build. - * dbus/dbus-errors.h: + * dbus/dbus-errors.h: * dbus/dbus-errors.c: Fix copyright for Anders. 2003-02-13 Anders Carlsson * bus/Makefile.am: Add utils.[ch] - + * bus/connection.c: (bus_connection_foreach): Fix a warning. - + * bus/desktop-file.c: (grow_lines_in_section), (grow_sections), (unescape_string), (new_section), (parse_section_start), (parse_key_value), (report_error), (bus_desktop_file_load), (bus_desktop_file_get_string): * bus/desktop-file.h: Use DBusError for error reporting. - + * bus/dispatch.c: (send_one_message), (bus_dispatch_message_handler): * bus/driver.c: (bus_driver_send_service_deleted), @@ -3345,21 +3355,21 @@ * bus/loop.c: (bus_loop_run): * bus/main.c: Use BUS_HANDLE_OOM instead of _DBUS_HANDLE_OOM. - + * bus/utils.c: (bus_wait_for_memory): * bus/utils.h: New files with general utility functions. - + * dbus/dbus-internals.h: Remove _DBUS_HANDLE_OOM. - + 2003-02-13 Anders Carlsson * dbus/dbus-errors.c: (dbus_result_to_string), (dbus_error_init), (dbus_error_free), (dbus_set_error_const), (dbus_set_error): * dbus/dbus-errors.h: Add DBusError structure. - + 2003-02-13 Anders Carlsson * test/data/valid-messages/standard-acquire-service.message: @@ -3367,7 +3377,7 @@ * test/data/valid-messages/standard-list-services.message: * test/data/valid-messages/standard-service-exists.message: Add some standard messages. - + 2003-02-13 Anders Carlsson * bus/driver.c: (bus_driver_send_welcome_message), @@ -3375,7 +3385,7 @@ (bus_driver_handle_acquire_service), (bus_driver_handle_service_exists), (bus_driver_handle_message): Update for API changes in libdbus. - + * dbus/dbus-message.c: (dbus_message_new_reply): * dbus/dbus-message.h: Remove the name argument. The spec states that replies shouldn't @@ -3389,7 +3399,7 @@ (bus_desktop_file_get_string): * bus/desktop-file.h: Some fixes, and new functions for getting a key value from a section. - + 2003-02-13 Havoc Pennington * test/data/auth/fail-after-n-attempts.auth-script: new test @@ -3405,12 +3415,12 @@ * dbus/dbus-auth-script.c (_dbus_auth_script_run): support NO_CREDENTIALS and ROOT_CREDENTIALS - * dbus/dbus-auth.c (_dbus_auth_do_work): move get_state() routine - into here. Never process more commands after we've reached an + * dbus/dbus-auth.c (_dbus_auth_do_work): move get_state() routine + into here. Never process more commands after we've reached an end state; store further data as unused bytes. * test/data/auth/*: add more auth tests - + * dbus/dbus-auth-script.c (_dbus_auth_script_run): support EXPECT command to match exact string and EXPECT_UNUSED to match unused bytes @@ -3438,11 +3448,11 @@ 2003-02-10 Havoc Pennington - * dbus/dbus-auth-script.c, dbus/dbus-auth-script.h: sync + * dbus/dbus-auth-script.c, dbus/dbus-auth-script.h: sync initial cut at test framework for DBusAuth from laptop. - Doesn't quite work yet but it compiles and I need to get + Doesn't quite work yet but it compiles and I need to get it off the 266mhz laptop. ;-) - + * dbus/dbus-server-debug.c (_dbus_server_debug_accept_transport): fix a memleak in error case @@ -3466,7 +3476,7 @@ 2003-02-06 Anders Carlsson Release 0.3 - + * NEWS: Update 2003-02-06 Anders Carlsson @@ -3479,7 +3489,7 @@ 2003-02-02 Havoc Pennington - * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files + * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files for code to manage cookies in your home directory * dbus/dbus-sysdeps.c (_dbus_generate_random_bytes): new function @@ -3496,7 +3506,7 @@ * doc/dbus-specification.sgml: Update address format section. - + 2003-02-02 Anders Carlsson * test/Makefile.am: @@ -3504,15 +3514,15 @@ (message_handler), (new_connection_callback), (loop_quit), (loop_run), (main): Add bus test. - + 2003-02-02 Anders Carlsson * bus/driver.c: (bus_driver_handle_service_exists): Simplify the code a bit. - + * dbus/dbus-bus.c: (dbus_bus_service_exists): - Fix a silly. - + Fix a silly. + 2003-02-02 Anders Carlsson * bus/Makefile.am: @@ -3527,7 +3537,7 @@ * bus/driver.c: (bus_driver_handle_service_exists): Don't unref the incoming message. - + 2003-02-02 Anders Carlsson * dbus/dbus.h: Add dbus-address.h and dbus-bus.h @@ -3537,7 +3547,7 @@ * dbus/dbus-server.c: (dbus_server_listen): * dbus/dbus-transport.c: (_dbus_transport_open): ifdef out the calls to the debug transport and server. - + 2003-02-02 Alexander Larsson * dbus/dbus-watch.c (dbus_watch_get_flags): @@ -3557,18 +3567,18 @@ (bus_driver_handle_hello): Don't take a name, just use a numeric id to identify each client. - + * dbus/Makefile.am: * dbus/dbus-bus.c: (dbus_bus_register_client), (dbus_bus_acquire_service), (dbus_bus_service_exists): * dbus/dbus-bus.h: Add new convenience functions for communicating with the bus. - + * dbus/dbus-message.h: - + * dbus/dbus-protocol.h: Fix a typo. - + 2003-02-01 Alexander Larsson * dbus/dbus-message.c (dbus_message_append_fields): @@ -3576,7 +3586,7 @@ 2003-02-01 Havoc Pennington - * dbus/dbus-break-loader.c (randomly_modify_length): change + * dbus/dbus-break-loader.c (randomly_modify_length): change a 4-byte value in the message as if it were a length * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): don't set @@ -3591,23 +3601,23 @@ * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): new function * dbus/dbus-string.c (_dbus_string_set_byte): new - + 2003-01-31 Havoc Pennington - * dbus/dbus-message.c: refactor the test code to be more general, - in preparation for writing a "randomly permute test cases to + * dbus/dbus-message.c: refactor the test code to be more general, + in preparation for writing a "randomly permute test cases to try to break the loader" program. 2003-01-31 Havoc Pennington - + * doc/dbus-specification.sgml: work on the specification - * dbus/dbus-message.c (_dbus_message_loader_return_buffer): check + * dbus/dbus-message.c (_dbus_message_loader_return_buffer): check the protocol version of the message. - * dbus/dbus-protocol.h: drop special _REPLY names, the spec + * dbus/dbus-protocol.h: drop special _REPLY names, the spec no longer specifies that. - (DBUS_SERVICE_REPLY_SERVICE_EXISTS): fix flags (1/2/4/8 not + (DBUS_SERVICE_REPLY_SERVICE_EXISTS): fix flags (1/2/4/8 not 1/2/3/4) * dbus/dbus-marshal.c (_dbus_marshal_get_arg_end_pos): add missing @@ -3615,7 +3625,7 @@ 2003-01-31 Havoc Pennington - * dbus/dbus-message.c (dbus_message_set_is_error_reply): rename + * dbus/dbus-message.c (dbus_message_set_is_error_reply): rename just set_is_error/get_is_error as this is a commonly-used function, and write docs. @@ -3623,28 +3633,28 @@ * dbus/dbus-address.c: (dbus_address_entry_free): Free key and value lists. - + * dbus/dbus-internals.c: (_dbus_type_to_string): Add the types we didn't have. - + * dbus/dbus-marshal.c: (_dbus_marshal_get_arg_end_pos), (_dbus_marshal_validate_arg): Add NIL types. - + * dbus/dbus-message.c: (dbus_message_set_sender): Remove todo about being able to set sender to NULL. - + (dbus_message_set_is_error_reply), (dbus_message_get_is_error_reply): * dbus/dbus-message.h: New functions. - + * dbus/dbus-protocol.h: Add error reply flag. - + * test/data/valid-messages/opposite-endian.message: Add NIL type to test. - + 2003-01-31 Havoc Pennington * doc/dbus-specification.sgml: fully specify the header. Add @@ -3661,10 +3671,10 @@ 2003-01-30 Havoc Pennington - * dbus/dbus-auth.c: rework to use only REJECTED, no + * dbus/dbus-auth.c: rework to use only REJECTED, no MECHANISMS - * doc/dbus-sasl-profile.txt: drop MECHANISMS and just + * doc/dbus-sasl-profile.txt: drop MECHANISMS and just use REJECTED, suggested by Mark McLoughlin 2003-01-30 Havoc Pennington @@ -3676,55 +3686,55 @@ * dbus/dbus-address.c (dbus_address_entries_free): add @todo about leaking list nodes - (dbus_parse_address): add @todo about documenting address format, + (dbus_parse_address): add @todo about documenting address format, and allowing , and ; to be escaped 2003-01-30 Anders Carlsson * dbus/Makefile.am: Add dbus-address.[ch] - + * dbus/dbus-address.c: (dbus_address_entry_free), (dbus_address_entries_free), (create_entry), (dbus_address_entry_get_method), (dbus_address_entry_get_value), (dbus_parse_address), (_dbus_address_test): * dbus/dbus-address.h: New files for dealing with address parsing. - + * dbus/dbus-connection.c: Document timeout functions. - + * dbus/dbus-message.c: Document dbus_message_new_from_message. - + * dbus/dbus-server-debug.c: Document. - + * dbus/dbus-server.c: (dbus_server_listen): Parse address and use correct server implementation. - + * dbus/dbus-string.c: (_dbus_string_find_to), (_dbus_string_test): * dbus/dbus-string.h: New function with test. - + * dbus/dbus-test.c: (dbus_internal_symbol_do_not_use_run_tests): * dbus/dbus-test.h: Add address tests. - + * dbus/dbus-transport-debug.c: Document. - + * dbus/dbus-transport.c: (_dbus_transport_open): - Parse address and use correct transport implementation. + Parse address and use correct transport implementation. 2003-01-30 Havoc Pennington - * dbus/dbus-message.c: use message->byte_order instead of + * dbus/dbus-message.c: use message->byte_order instead of DBUS_COMPILER_BYTE_ORDER throughout. - (dbus_message_create_header): pad header to align the + (dbus_message_create_header): pad header to align the start of the body of the message to 8-byte boundary - * dbus/dbus-marshal.h: make all the demarshalers take const + * dbus/dbus-marshal.h: make all the demarshalers take const DBusString arguments. * dbus/dbus-message.c (_dbus_message_loader_return_buffer): @@ -3737,7 +3747,7 @@ implemented properly) (_dbus_string_validate_nul): new function to check all-nul - * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename + * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename get_arg_end_pos and remove all validation (_dbus_marshal_validate_arg): actually do validation here. @@ -3749,9 +3759,9 @@ 2003-01-28 Havoc Pennington * dbus/dbus-server-debug.c: Add doc section comments - + * dbus/dbus-transport-debug.c: add doc section comments - + 2003-01-28 Havoc Pennington * dbus/dbus-string.c (_dbus_string_base64_decode): append bytes in @@ -3765,13 +3775,13 @@ * dbus/dbus-connection.c: (_dbus_connection_add_timeout), (_dbus_connection_remove_timeout): Add functions for adding and removing timeouts. - + * dbus/dbus-message.c: (dbus_message_new_from_message): Add new function that takes a message and creates an exact copy of it, but with the refcount set to 1. (check_message_handling): Fix build error. - + * dbus/dbus-server-protected.h: * dbus/dbus-server.c: (_dbus_server_init_base), (_dbus_server_finalize_base), (_dbus_server_add_timeout), @@ -3784,16 +3794,16 @@ * dbus/dbus-timeout.c: (_dbus_timeout_new): Actually set the handler, doh. - + * dbus/dbus-transport.c: (_dbus_transport_open): Add commented out call to dbus_transport_debug_client_new. - + * dbus/Makefile.am: Add dbus-transport-debug.[ch] and dbus-server-debug.[ch] - + 2003-01-28 Havoc Pennington - * dbus/dbus-message.c (check_message_handling): function to check + * dbus/dbus-message.c (check_message_handling): function to check on the loaded message, iterates over it etc. 2003-01-28 Havoc Pennington @@ -3804,14 +3814,14 @@ 2003-01-27 Havoc Pennington - * dbus/dbus-mempool.c (time_for_size): replace printf with + * dbus/dbus-mempool.c (time_for_size): replace printf with _dbus_verbose * dbus/dbus-message-builder.c (_dbus_message_data_load): allow empty lines; fix the SAVE_LENGTH stuff to be - START_LENGTH/END_LENGTH so it actually works; couple other + START_LENGTH/END_LENGTH so it actually works; couple other bugfixes - + * test/Makefile.am (dist-hook): add dist-hook for .message files * dbus/dbus-string.c (DBUS_STRING_COPY_PREAMBLE): source of a copy @@ -3821,7 +3831,7 @@ * dbus/dbus-sysdeps.c (_dbus_concat_dir_and_file): utility - * dbus/dbus-test-main.c (main): take an argument which is the + * dbus/dbus-test-main.c (main): take an argument which is the directory containing test data * dbus/dbus-message.c (_dbus_message_test): pass a test_data_dir @@ -3832,7 +3842,7 @@ * bus/dispatch.c: (bus_dispatch_message_handler): Dispatch messages sent to services. - + * bus/driver.c: (bus_driver_send_service_deleted), (bus_driver_send_service_created), (bus_driver_send_service_lost), (bus_driver_send_service_acquired): @@ -3840,56 +3850,56 @@ (bus_driver_send_welcome_message): Send HELLO_REPLY instead of WELCOME. - + (bus_driver_handle_list_services): Send LIST_SERVICES_REPLY instead of SERVICES. - + (bus_driver_handle_own_service), (bus_driver_handle_service_exists): New message handlers. - + (bus_driver_handle_message): Invoke new message handlers. - + (bus_driver_remove_connection): Don't remove any services here since that's done automatically by bus_service_remove_owner now. - + * bus/driver.h: New function signatures. - + * bus/services.c: (bus_service_add_owner): Send ServiceAcquired message if we're the only primary owner. - + (bus_service_remove_owner): Send ServiceAcquired/ServiceLost messages. - + (bus_service_set_prohibit_replacement), (bus_service_get_prohibit_replacement): Functions for setting prohibit replacement. - + (bus_service_has_owner): - New function that checks if a connection is in the owner queue of + New function that checks if a connection is in the owner queue of a certain service. - + * bus/services.h: Add new function signatures. - + * dbus/dbus-list.c: (_dbus_list_test): Add tests for _dbus_list_remove_last and traversing the list backwards. - + * dbus/dbus-list.h: Fix a typo in _dbus_list_get_prev_link, if we're at the first element we can't go any further, so return NULL then. - + * dbus/dbus-protocol.h: Add new messages, service flags and service replies. - + 2003-01-26 Havoc Pennington * dbus/dbus-message-builder.c: implement, completely untested. - * test/data/*: add data to be used in testing. + * test/data/*: add data to be used in testing. ".message" files are our simple loadable text format. ".message-raw" will be binary dumps of messages. @@ -3914,21 +3924,21 @@ The unit tests pass, but otherwise untested. If it breaks, the tests should have been better. ;-) - + * bus/driver.c (bus_driver_handle_hello): return if we disconnect the connection. - * dbus/dbus-message.c: redo everything so we maintain + * dbus/dbus-message.c: redo everything so we maintain message->header as the only copy of the various fields. This avoids the possibility of out-of-memory in some cases, for example dbus_message_lock() can't run out of memory anymore, - and avoids extra copying. Figured I may as well go ahead and do - this since it was busted for dbus_message_lock to not return + and avoids extra copying. Figured I may as well go ahead and do + this since it was busted for dbus_message_lock to not return failure on OOM, and dbus_message_write_header was totally unchecked for OOM. Also fixed some random other bugs. * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): verify - that strings are nul-terminated. Also, end_pos can be equal + that strings are nul-terminated. Also, end_pos can be equal to string length just not greater than, I think. (_dbus_marshal_set_int32): new function (_dbus_marshal_set_uint32): new function @@ -3946,7 +3956,7 @@ * bus/driver.c: (bus_driver_handle_hello), (bus_driver_send_welcome_message): Plug leaks - + 2003-01-26 Anders Carlsson * dbus/dbus-auth.c: (process_auth), (_dbus_auth_unref): @@ -3955,13 +3965,13 @@ * dbus/dbus-marshal.c: (_dbus_marshal_test): * dbus/dbus-message.c: (dbus_message_unref), Plug memory leaks. - - (dbus_message_get_fields): + + (dbus_message_get_fields): Remove debugging printout. (_dbus_message_loader_return_buffer): Don't store the header string. - + (_dbus_message_test): Plug leaks. @@ -3975,10 +3985,10 @@ * glib/dbus-gmain.c: (dbus_connection_prepare), (dbus_connection_check), (dbus_connection_dispatch), (add_watch), (remove_watch), (dbus_connection_hookup_with_g_main): - Rewrite the glib handling to use its own GSource instead of a + Rewrite the glib handling to use its own GSource instead of a GIOChannel so we can catch messages put in the queue while waiting for a reply. - + 2003-01-25 Anders Carlsson * bus/Makefile.am: @@ -3994,105 +4004,105 @@ (bus_driver_handle_list_services), (bus_driver_remove_connection), (bus_driver_handle_message): * bus/driver.h: - Refactor code, put the message dispatching in its own file. Use + Refactor code, put the message dispatching in its own file. Use _DBUS_HANDLE_OOM. Also send ServiceDeleted messages when a client is disconnected. - + 2003-01-25 Anders Carlsson * dbus/dbus-internals.h: Add _DBUS_HANDLE_OOM macro, it doesn't do anything currently. - + * dbus/dbus-message.c: (dbus_message_get_sender): * dbus/dbus-message.h: Implement dbus_message_get_sender. - + * dbus/dbus-protocol.h: Add message and service defines. - + 2003-01-25 Anders Carlsson * dbus/dbus-connection.c: (dbus_connection_send_message): * dbus/dbus-message-internal.h: * dbus/dbus-message.c: (_dbus_message_get_client_serial), (dbus_message_write_header): - Remove _dbus_messag_unlock and don't set the client serial on a + Remove _dbus_messag_unlock and don't set the client serial on a message if one already exists. - + 2003-01-24 Havoc Pennington * dbus/dbus-list.c (alloc_link): put a thread lock on the global list_pool - * bus/driver.c (bus_driver_handle_list_services): fix a leak + * bus/driver.c (bus_driver_handle_list_services): fix a leak on OOM 2003-01-25 Anders Carlsson * dbus/dbus-list.c: (alloc_link), (free_link): Use a memory pool for the links. - + 2003-01-25 Anders Carlsson * bus/connection.c: (bus_connection_foreach): * bus/connection.h: Add new bus_connection_foreach function. - + * bus/driver.c: (send_one_message), (bus_driver_broadcast_message): Add function that broadcasts a message to all clients. - + (bus_driver_send_service_created), (bus_driver_handle_hello), (bus_driver_send_welcome_message), (bus_driver_handle_list_services), (bus_driver_message_handler): Implement functions that take care of listing services, and notifying clients when new services are created. - + * bus/services.c: (bus_services_list): * bus/services.h: Add new function that returns an array of strings with the currently registered services. - + * glib/dbus-glib.h: * glib/dbus-gmain.c: Update copyright year. - + 2003-01-25 Anders Carlsson * dbus/dbus-connection.c: (dbus_connection_send_message): Unlock the message in case it was sent earlier. - + (dbus_connection_send_message_with_reply_and_block): Remove the reply message from the list. - + * dbus/dbus-marshal.c: (_dbus_demarshal_string_array): Set array_len and new_pos correctly. - + (_dbus_marshal_test): Remove debug output. - + * dbus/dbus-message-internal.h: * dbus/dbus-message.c: (_dbus_message_get_reply_serial): New function that returns the reply serial. - + (_dbus_message_unlock): New function that unlocks a message and resets its header. - (dbus_message_append_string_array), + (dbus_message_append_string_array), (dbus_message_get_fields_valist), (dbus_message_iter_get_field_type), - (dbus_message_iter_get_string_array), - (dbus_message_get_fields), + (dbus_message_iter_get_string_array), + (dbus_message_get_fields), (dbus_message_append_fields_valist): Handle string arrays. - + (dbus_message_set_sender): Make this function public since the bus daemon needs it. - + (decode_header_data): Set the reply serial to -1 initially. * dbus/dbus-message.h: - Add dbus_message_set_sender. + Add dbus_message_set_sender. 2003-01-24 Havoc Pennington @@ -4112,9 +4122,9 @@ 2003-01-21 Havoc Pennington (patch untested because can't compile) - + * bus/driver.c (create_unique_client_name): make this function - never recycle client names. Also, caller should initialize + never recycle client names. Also, caller should initialize the DBusString. * dbus/dbus-sysdeps.c (_dbus_get_current_time): new function @@ -4132,27 +4142,27 @@ * dbus/dbus-protocol.h: Add support for marshalling and demarshalling integer, double and string arrays. - + 2003-01-21 Anders Carlsson * bus/Makefile.am: Add driver.[ch] - + * bus/connection.c: (connection_disconnect_handler): Remove the connection from the bus driver's list. - + (connection_watch_callback): Dispatch messages. (free_connection_data): Free connection name. - + (bus_connection_setup): Add connection to the bus driver's list. - (bus_connection_remove_owned_service): + (bus_connection_remove_owned_service): (bus_connection_set_name), (bus_connection_get_name): Add functions for setting and getting the connection's name. - + * bus/connection.h: Add function headers. - + * bus/driver.c: (create_unique_client_name), (bus_driver_handle_hello_message), (bus_driver_send_welcome_message), (bus_driver_message_handler), @@ -4162,27 +4172,27 @@ * bus/services.c: (bus_service_free): * bus/services.h: New file that handles communication and registreation with the bus - itself. - + itself. + 2003-01-21 Anders Carlsson * dbus/dbus-connection.c: (dbus_connection_send_message): Add a new client_serial parameter. - + (dbus_connection_send_message_with_reply): Remove a @todo since we've implemented the blocking function. - + (dbus_connection_send_message_with_reply_and_block): New function that sends a message and waits for a reply and then returns the reply. - + * dbus/dbus-connection.h: Add new functions. - + * dbus/dbus-errors.c: (dbus_result_to_string): * dbus/dbus-errors.h: Add new DBUS_RESULT. - + * dbus/dbus-message-internal.h: * dbus/dbus-message.c: (_dbus_message_get_reply_serial), (_dbus_message_set_sender), (dbus_message_write_header), @@ -4191,37 +4201,37 @@ * dbus/dbus-message.h: Add new functions that set the reply serial and sender. Also marshal and demarshal them correctly and add test. - + * dbus/dbus-protocol.h: Add new DBUS_MESSAGE_TYPE_SENDER. - + * glib/dbus-glib.h: * glib/dbus-gmain.c: (watch_callback), (free_callback_data), (add_watch), (remove_watch), (add_timeout), (remove_timeout), (dbus_connection_hookup_with_g_main): * glib/test-dbus-glib.c: (main): Rewrite to use GIOChannel and remove the GSource crack. - + * test/echo-client.c: (main): * test/watch.c: (check_messages): Update for changed APIs - + 2003-01-19 Anders Carlsson * dbus/Makefile.am: Add dbus-timeout.[cħ] - + * dbus/dbus-connection.c: (_dbus_connection_new_for_transport): - Create a DBusTimeoutList. + Create a DBusTimeoutList. (dbus_connection_set_timeout_functions): Add new function to set timeout callbacks - + * dbus/dbus-connection.h: Add public DBusTimeout API. - + * dbus/dbus-message.c: (dbus_message_get_service): * dbus/dbus-message.h: New function. * dbus/dbus-server.c: Fix small doc typo. - + * dbus/dbus-timeout.[ch]: New files for mainloop timeouts. 2003-01-19 Anders Carlsson @@ -4251,9 +4261,9 @@ * dbus/dbus-transport-unix.c (check_write_watch): fix a mem leak in OOM case - * dbus/dbus-connection.c (dbus_connection_set_max_message_size) - (dbus_connection_get_max_message_size) - (dbus_connection_set_max_live_messages_size) + * dbus/dbus-connection.c (dbus_connection_set_max_message_size) + (dbus_connection_get_max_message_size) + (dbus_connection_set_max_live_messages_size) (dbus_connection_get_max_live_messages_size): implement some resource limitation functions @@ -4265,10 +4275,10 @@ * dbus/dbus-marshal.c (_dbus_demarshal_byte_array): add missing docs - + 2003-01-18 Havoc Pennington - * dbus/dbus-connection.c (dbus_connection_unref): disconnect the + * dbus/dbus-connection.c (dbus_connection_unref): disconnect the connection if it hasn't been already. * dbus/dbus-connection.h: kill off the idea of an ErrorFunction, @@ -4278,9 +4288,9 @@ Building --disable-verbose-mode --disable-asserts --disable-tests cuts the library from 112K to 45K or so - - * configure.in: check for varargs macro support, - add --enable-verbose-mode, --enable-asserts. + + * configure.in: check for varargs macro support, + add --enable-verbose-mode, --enable-asserts. * dbus/dbus-internals.h (_dbus_assert): support DBUS_DISABLE_ASSERT @@ -4307,7 +4317,7 @@ 2003-01-15 Havoc Pennington Release 0.2 - + * NEWS: update 2003-01-15 Havoc Pennington @@ -4318,8 +4328,8 @@ 2003-01-15 Havoc Pennington Release 0.1. - - * NEWS: update + + * NEWS: update 2003-01-15 Havoc Pennington @@ -4337,7 +4347,7 @@ * bus/main.c: (main): Make sure that the DBusConnectionData struct is NULLed out to prevent a segfault. - + * dbus/dbus-errors.c: (dbus_result_to_string): * dbus/dbus-errors.h: * dbus/dbus-message.c: (dbus_message_get_fields), @@ -4345,7 +4355,7 @@ * dbus/dbus-message.h: Make dbus_message_get_fields return a result code so we can track invalid fields as well as oom. - + 2003-01-11 Havoc Pennington * configure.in: change --enable-test/--enable-ansi action-if-given @@ -4358,11 +4368,11 @@ * dbus/dbus-test-main.c: move main() for test app here * dbus/dbus-test.c (dbus_internal_symbol_do_not_use_run_tests): we have to export a - symbol to run tests, because dbus-test isn't in the main + symbol to run tests, because dbus-test isn't in the main library Code review nitpicks. - + * dbus/dbus-message.c (dbus_message_write_header): add newlines for people with narrow emacs ;-). Assert client_serial was filled in. Assert message->name != NULL. @@ -4399,7 +4409,7 @@ 2003-01-08 Havoc Pennington - * dbus/dbus-transport-unix.c (unix_do_iteration): add read/write + * dbus/dbus-transport-unix.c (unix_do_iteration): add read/write to the select() as needed for authentication. (should be using _dbus_poll() not select, but for another day) @@ -4414,7 +4424,7 @@ * dbus/dbus-internals.c: (_dbus_type_to_string): New function that returns a string describing a type. - + * dbus/dbus-marshal.c: (_dbus_demarshal_byte_array): * dbus/dbus-marshal.h: * dbus/dbus-message.c: (dbus_message_get_fields_valist), @@ -4460,7 +4470,7 @@ * test/echo-client.c: (main): * test/watch.c: (check_messages): Make messages sendable and receivable for real. - + 2003-01-07 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_double), @@ -4469,7 +4479,7 @@ (dbus_message_append_uint32), (dbus_message_append_double), (dbus_message_append_string), (dbus_message_append_byte_array): Handle OOM restoration. - + 2003-01-07 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_string), @@ -4477,13 +4487,13 @@ * dbus/dbus-marshal.h: * dbus/dbus-message.c: (dbus_message_get_name), Document these functions. - + (dbus_message_append_int32), (dbus_message_append_uint32), (dbus_message_append_double), (dbus_message_append_string), (dbus_message_append_byte_array): * dbus/dbus-message.h: Add functions for adding message fields of different types. - + * dbus/dbus-protocol.h: Add the different types. @@ -4517,13 +4527,13 @@ 2003-01-04 Havoc Pennington - * test/watch.c (error_handler): make it safe if the error handler + * test/watch.c (error_handler): make it safe if the error handler is called multiple times (if we s/error handler/disconnect handler/ we should just guarantee it's called only once) * dbus/dbus-transport.c (_dbus_transport_disconnect): call the error handler on disconnect (it's quite possible we should - just change the error handler to a "disconnect handler," I'm + just change the error handler to a "disconnect handler," I'm not sure we have any other meaningful errors) * configure.in: check for getpwnam_r @@ -4548,7 +4558,7 @@ * dbus/dbus-marshal.h: Add _dbus_marshal_byte_array and rename _dbus_marshal_string to _dbus_marshal_utf8_string. Also fix some tests. - + 2002-12-28 Harri Porten * configure.in: added check for C++ compiler and a very cheesy @@ -4556,9 +4566,9 @@ * Makefile.am (SUBDIRS): compile qt subdir if support is enabled - * qt/Makefile.am: added + * qt/Makefile.am: added - * qt/.cvsignore: added + * qt/.cvsignore: added * qt/dbus-qthread.cc, qt/dbus-qthread.cpp: renamed former to latter, added #ifdef QT_THREAD_SUPPORT guard. @@ -4571,7 +4581,7 @@ 2002-12-27 Anders Carlsson - * acinclude.m4: Add this file and put the + * acinclude.m4: Add this file and put the PKG_CHECK_MODULE macro in it. 2002-12-27 Anders Carlsson @@ -4581,9 +4591,9 @@ (_dbus_demarshal_uint32), (_dbus_demarshal_string), (_dbus_marshal_test): Make the demarshalling routines align the pos argument. - Add string marshalling tests and fix the obvious bugs + Add string marshalling tests and fix the obvious bugs discovered. - + 2002-12-26 Havoc Pennington * dbus/dbus-auth.c: fixes fixes fixes @@ -4591,8 +4601,8 @@ * dbus/dbus-transport-unix.c: wire up support for encoding/decoding data on the wire - * dbus/dbus-auth.c (_dbus_auth_encode_data) - (_dbus_auth_decode_data): append to target string + * dbus/dbus-auth.c (_dbus_auth_encode_data) + (_dbus_auth_decode_data): append to target string instead of nuking it. 2002-12-26 Havoc Pennington @@ -4602,7 +4612,7 @@ doh * dbus/dbus-marshal.c: Add macros to do int swapping in-place and - avoid swap_bytes() overhead (ignoring possible assembly stuff for + avoid swap_bytes() overhead (ignoring possible assembly stuff for now). Main point is because I wanted unpack_uint32 to implement _dbus_verbose_bytes (_dbus_verbose_bytes): new function @@ -4611,14 +4621,14 @@ * dbus/dbus-message.c (_dbus_message_loader_get_is_corrupted): add mechanism to handle a corrupt message stream - (_dbus_message_loader_new): fix preallocation to only prealloc, + (_dbus_message_loader_new): fix preallocation to only prealloc, not prelengthen - + * dbus/dbus-string.c (_dbus_string_skip_blank): fix this function (_dbus_string_test): enhance tests for copy/move and fix the functions - * dbus/dbus-transport-unix.c: Hold references in more places to + * dbus/dbus-transport-unix.c: Hold references in more places to avoid reentrancy problems * dbus/dbus-transport.c: ditto @@ -4638,7 +4648,7 @@ (_dbus_auth_get_unused_bytes): append the unused bytes to the passed in string, rather than prepend - * dbus/dbus-transport.c (_dbus_transport_init_base): create + * dbus/dbus-transport.c (_dbus_transport_init_base): create the auth conversation DBusAuth * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd) @@ -4653,14 +4663,14 @@ (unix_connection_set): unref watch if we fail to add it * dbus/dbus-connection.c (dbus_connection_unref): delete the - transport first, so that the connection owned by the + transport first, so that the connection owned by the transport will be valid as the transport finalizes. * dbus/dbus-transport-unix.c (unix_finalize): free the write_watch if necessary, and remove watches from the connection. - + * dbus/dbus-watch.c (_dbus_watch_list_free): improve a comment - + 2002-12-26 Anders Carlsson * dbus/dbus-marshal.c: (_dbus_marshal_string), @@ -4670,15 +4680,15 @@ * dbus/dbus-marshal.h: Add string marshal functions and have the demarshal functions return the new position. - + 2002-12-25 Havoc Pennington - * doc/dbus-sasl-profile.txt: docs on the authentication protocol, + * doc/dbus-sasl-profile.txt: docs on the authentication protocol, it is a simple protocol that just maps directly to SASL. * dbus/dbus-auth.h, dbus/dbus-auth.c: authentication protocol initial implementation, not actually used yet. - + * dbus/dbus-string.c (_dbus_string_find): new function (_dbus_string_equal): new function (_dbus_string_base64_encode): new function @@ -4696,7 +4706,7 @@ * dbus/dbus-test.c: (main): * dbus/dbus-test.h: Add un-optimized marshalling/demarshalling routines. - + 2002-12-25 Harri Porten * qt/dbus-qt.h: adjusted ctor and getter to KDE/Qt conventions @@ -4711,17 +4721,17 @@ * glib/dbus-gthread.c: fix include - * glib/dbus-glib.h: rename DBusMessageHandler for now. - I think glib API needs to change, though, as you don't - want to use DBusMessageFunction, you want to use the - DBusMessageHandler object. Probably + * glib/dbus-glib.h: rename DBusMessageHandler for now. + I think glib API needs to change, though, as you don't + want to use DBusMessageFunction, you want to use the + DBusMessageHandler object. Probably dbus_connection_open_with_g_main_loop() and dbus_connection_setup_g_main_loop() or something like that - (but think of better names...) that just create a connection + (but think of better names...) that just create a connection that has watch/timeout functions etc. already set up. * dbus/dbus-connection.c - (dbus_connection_send_message_with_reply): new function just to + (dbus_connection_send_message_with_reply): new function just to show how the message handler helps us deal with replies. * dbus/dbus-list.c (_dbus_list_remove_last): new function @@ -4730,15 +4740,15 @@ wasn't * dbus/dbus-hash.c: use memory pools for the hash entries - (rebuild_table): be more paranoid about overflow, and + (rebuild_table): be more paranoid about overflow, and shrink table when we can (_dbus_hash_test): reduce number of sprintfs and write - valid C89. Add tests for case where we grow and then + valid C89. Add tests for case where we grow and then shrink the hash table. * dbus/dbus-mempool.h, dbus/dbus-mempool.c: memory pools - * dbus/dbus-connection.c (dbus_connection_register_handler) + * dbus/dbus-connection.c (dbus_connection_register_handler) (dbus_connection_unregister_handler): new functions * dbus/dbus-message.c (dbus_message_get_name): new @@ -4753,13 +4763,13 @@ * glib/dbus-glib.h: * glib/dbus-gthread.c: (dbus_gthread_init): Don't use the gdbus prefix for public functions. - + 2002-12-16 Anders Carlsson * Makefile.am: * configure.in: Add GLib checks and fixup .pc files - + * glib/Makefile.am: * glib/dbus-glib.h: * glib/dbus-gmain.c: (gdbus_connection_prepare), @@ -4770,14 +4780,14 @@ (dbus_gmutex_lock), (dbus_gmutex_unlock), (dbus_gthread_init): * glib/test-dbus-glib.c: (message_handler), (main): Add GLib support. - + 2002-12-15 Harri Porten - * autogen.sh: check for libtoolize before attempting to use it - + * autogen.sh: check for libtoolize before attempting to use it + * dbus/dbus-transport-unix.c: include for timeval struct. - + * .cvsignore: ignore more stamp files * dbus/dbus-watch.c (_dbus_watch_list_new): fixed doc error @@ -4815,7 +4825,7 @@ * dbus/dbus-connection.c (dbus_connection_send_message): return TRUE on success - * dbus/dbus-transport.c: include dbus-watch.h + * dbus/dbus-transport.c: include dbus-watch.h * dbus/dbus-connection.c: include dbus-message-internal.h @@ -4829,17 +4839,17 @@ system/libc usage here, as in vsftpd, for ease of auditing (and should also simplify portability). Haven't actually moved all the system/libc usage into here yet. - + 2002-11-25 Havoc Pennington - * dbus/dbus-internals.c (_dbus_verbose): fix to not + * dbus/dbus-internals.c (_dbus_verbose): fix to not always print the first verbose message. 2002-11-24 Havoc Pennington - * test/echo-client.c, test/echo-server.c: cheesy test + * test/echo-client.c, test/echo-server.c: cheesy test clients. - + * configure.in (AC_CHECK_FUNCS): check for writev * dbus/dbus-message.c (_dbus_message_get_network_data): new @@ -4858,8 +4868,8 @@ public API for reporting errors * dbus/dbus-connection.h, dbus/dbus-connection.c: - public object representing a connection that - sends/receives messages. (Same object used for + public object representing a connection that + sends/receives messages. (Same object used for both client and server.) * dbus/dbus-transport.h, dbus/dbus-transport.c: @@ -4868,20 +4878,20 @@ 2002-11-23 Havoc Pennington - * dbus/dbus-internals.h (_DBUS_INT_MAX): add _DBUS_INT_MIN + * dbus/dbus-internals.h (_DBUS_INT_MAX): add _DBUS_INT_MIN _DBUS_INT_MAX - * dbus/dbus-test.c (main): add list test, and include + * dbus/dbus-test.c (main): add list test, and include dbus-test.h as intended - * dbus/dbus-hash.c (_dbus_hash_table_remove_string) - (_dbus_hash_table_remove_int): return value indicates + * dbus/dbus-hash.c (_dbus_hash_table_remove_string) + (_dbus_hash_table_remove_int): return value indicates whether the entry existed to remove - * dbus/dbus-list.c: add linked list utility class, + * dbus/dbus-list.c: add linked list utility class, with docs and tests - * dbus/dbus-hash.c: add TODO item about shrinking the hash bucket + * dbus/dbus-hash.c: add TODO item about shrinking the hash bucket array sometimes. 2002-11-23 Havoc Pennington @@ -4891,43 +4901,43 @@ * Doxyfile.in (JAVADOC_AUTOBRIEF): set to YES - * dbus/dbus-message.c, dbus/dbus-hash.c: + * dbus/dbus-message.c, dbus/dbus-hash.c: add some missing @brief 2002-11-23 Havoc Pennington - * dbus/dbus-message.h: put semicolons after DEBUG_BEGIN_DECLS + * dbus/dbus-message.h: put semicolons after DEBUG_BEGIN_DECLS to avoid confusing Doxygen * dbus/dbus-hash.c: @} not }@ - * dbus/dbus-message.c (struct DBusMessage): split out + * dbus/dbus-message.c (struct DBusMessage): split out internals docs 2002-11-23 Havoc Pennington * configure.in: pile on more warning flags if using gcc - * Doxyfile.in (EXTRACT_STATIC): set to NO, so we don't have + * Doxyfile.in (EXTRACT_STATIC): set to NO, so we don't have to document static functions - * configure.in: add summary to end of configure so it + * configure.in: add summary to end of configure so it looks nice and attractive - * dbus/dbus-hash.c: finish implementation and write unit + * dbus/dbus-hash.c: finish implementation and write unit tests and docs * configure.in: add --enable-tests to enable unit tests - * dbus/dbus-test.c: test program to run unit tests - for all files in dbus/*, initially runs a test for + * dbus/dbus-test.c: test program to run unit tests + for all files in dbus/*, initially runs a test for dbus-hash.c - + * dbus/dbus-internals.h: file to hold some internal utility stuff 2002-11-22 Havoc Pennington - * dbus/dbus-hash.c: copy in Tcl hash table, not yet + * dbus/dbus-hash.c: copy in Tcl hash table, not yet "ported" away from Tcl * dbus/dbus-types.h: header for types such as dbus_bool_t @@ -4936,7 +4946,7 @@ * dbus/dbus.h: fixups for doc warnings - * Doxyfile.in (FILE_PATTERNS): we need to scan .h to pick up + * Doxyfile.in (FILE_PATTERNS): we need to scan .h to pick up macros (QUIET): make it quiet so we can see warnings @@ -4948,8 +4958,8 @@ * configure.in: generate the Doxyfile - * Doxyfile.in: move Doxyfile here, so we can use - configure to generate a Doxyfile with the right + * Doxyfile.in: move Doxyfile here, so we can use + configure to generate a Doxyfile with the right version number etc. 2002-11-22 Havoc Pennington @@ -4958,16 +4968,16 @@ * Doxyfile (OUTPUT_DIRECTORY): move output to doc/api so all docs are under doc/ - (MAN_EXTENSION): generate man pages. Use extension - ".3dbus" which matches ".3qt" on my system, + (MAN_EXTENSION): generate man pages. Use extension + ".3dbus" which matches ".3qt" on my system, I guess this is OK, I don't know really. (FILE_PATTERNS): look for .c files not .h, makes sense for plain C I think 2002-11-22 Havoc Pennington - * Makefile.am (SUBDIRS): rename subdir "server" to "bus" - because any app can be a server, and any app can be a client, + * Makefile.am (SUBDIRS): rename subdir "server" to "bus" + because any app can be a server, and any app can be a client, the bus is a special kind of server. Thu Nov 21 23:35:31 2002 Zack Rusin @@ -4975,7 +4985,7 @@ Thu Nov 21 23:35:31 2002 Zack Rusin * Doxyfile : adding. Still needs Makefile rules to be generated automatically (just run "doxygen" in the toplevel dir for now to generate docs) - + * dbus/dbus-message.h : Adding sample docs (javadoc since resembles gtk-doc a little more) @@ -4983,17 +4993,17 @@ Thu Nov 21 23:35:31 2002 Zack Rusin 2002-11-21 Havoc Pennington - * dbus/Makefile.am (INCLUDES): define DBUS_COMPILATION - so we can allow ourselves to include files directly, + * dbus/Makefile.am (INCLUDES): define DBUS_COMPILATION + so we can allow ourselves to include files directly, instead of having to use dbus.h * dbus/dbus.h: fill in * dbus/dbus-message.h: sketch out a sample header file. - Include griping if you include it directly instead of + Include griping if you include it directly instead of via dbus.h - * dbus/dbus-macros.h: new file with macros for extern "C", + * dbus/dbus-macros.h: new file with macros for extern "C", TRUE/FALSE, NULL, etc. * doc/file-boilerplate.c: put include guards in here @@ -5002,7 +5012,7 @@ Thu Nov 21 23:35:31 2002 Zack Rusin * doc/file-boilerplate.c: include both AFL and GPL boilerplate. - * COPYING: include the GPL as well, and license code + * COPYING: include the GPL as well, and license code under both AFL and GPL. 2002-11-21 Havoc Pennington @@ -5012,9 +5022,9 @@ Thu Nov 21 23:35:31 2002 Zack Rusin * autogen.sh (run_configure): add --no-configure option * configure.in: remove AC_ARG_PROGRAM to make - autoconf complain less. add AC_PREREQ. + autoconf complain less. add AC_PREREQ. add AC_DEFINE third arg. - + 2002-11-21 Anders Carlsson * doc/Makefile.am: 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 v1.2.1 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 --- ChangeLog | 9 ++ 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 + 12 files changed, 415 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ed9055c..6cf65315 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +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 + 2003-07-08 Havoc Pennington * dbus/dbus-object.h: sketch out an API for registering objects 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 v1.2.1 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 --- ChangeLog | 11 + 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 + 8 files changed, 600 insertions(+), 269 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6cf65315..ea15a719 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +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 + 2003-07-08 Havoc Pennington * dbus/dbus-object.c: implement some of this 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 v1.2.1 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 --- ChangeLog | 5 +++++ dbus/dbus-connection.c | 8 ++++++-- dbus/dbus-object.c | 3 ++- dbus/dbus-object.h | 11 ++++++++--- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index ea15a719..3f74ff4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-07-13 Havoc Pennington + + * dbus/dbus-object.h (struct DBusObjectVTable): add padding + fields to DBusObjectVTable and DBusObjectInfo + 2003-07-12 Havoc Pennington * dbus/dbus-object-registry.c: implement unit test, 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 v1.2.1 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. --- ChangeLog | 29 ++++ 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 +- 11 files changed, 339 insertions(+), 147 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3f74ff4b..e7daf2bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +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. + +2003-07-30 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_register_object): fix + build + 2003-07-13 Havoc Pennington * dbus/dbus-object.h (struct DBusObjectVTable): add padding 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 v1.2.1 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 --- ChangeLog | 9 ++ 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 + doc/dbus-specification.sgml | 58 +++++++- test/data/invalid-messages/bad-endian.message | 2 +- test/data/valid-messages/simplest-manual.message | 2 +- 12 files changed, 309 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index e7daf2bc..2e961823 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +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 + 2003-08-01 Havoc Pennington * dbus/dbus-protocol.h (DBUS_MESSAGE_TYPE_*): introduce 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 diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index 68a71cec..a53be53d 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -133,6 +133,12 @@ Endianness flag; ASCII 'l' for little-endian or ASCII 'B' for big-endian. + + 1 byte + Type of message. Unknown types MUST be ignored. + Currently-defined types are described below. + + 1 byte Bitwise OR of flags. Unknown flags @@ -148,12 +154,6 @@ version for this version of the specification is 0. - - 1 byte - A nul byte, reserved for future use. - Any value for this byte MUST be accepted. - - 4 bytes An unsigned 32-bit integer in the @@ -182,7 +182,44 @@ - Flags that can appear in the second byte of the header: + Types that can appear in the second byte of the header: + + + + + Decimal value + Description + + + + + 0 + This is an invalid type, if seen in a message + the connection should be dropped immediately. + + + 1 + Method call. + + + + 2 + Method reply with returned data. + + + 3 + Error. + + + 4 + Signal emission. + + + + + + + Flags that can appear in the third byte of the header: @@ -196,6 +233,13 @@ 0x1 This message is an error reply. If the first argument exists and is a string, it is an error message. + + 0x2 + This message does not expect method return replies or + error replies; the reply can be omitted as an + optimization. However, it is compliant with this specification + to return the reply despite this flag. + diff --git a/test/data/invalid-messages/bad-endian.message b/test/data/invalid-messages/bad-endian.message index 7a7b75d1..b1432359 100644 --- a/test/data/invalid-messages/bad-endian.message +++ b/test/data/invalid-messages/bad-endian.message @@ -1,7 +1,7 @@ ## message with invalid endianness tag BYTE 'i' -BYTE 0 +BYTE 1 BYTE 0 BYTE 0 LENGTH Header diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message index 8eed1e5f..f0ecccdd 100644 --- a/test/data/valid-messages/simplest-manual.message +++ b/test/data/valid-messages/simplest-manual.message @@ -3,7 +3,7 @@ LITTLE_ENDIAN BYTE 'l' -BYTE 0 +BYTE 1 BYTE 0 BYTE 0 LENGTH Header -- cgit v1.2.1 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 --- ChangeLog | 9 +++++++++ dbus/dbus-message.c | 45 +++++++++++++++++++++++---------------------- dbus/dbus-message.h | 6 +++--- dbus/dbus-protocol.h | 3 +-- doc/dbus-specification.sgml | 7 ++----- 5 files changed, 38 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e961823..a5051388 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +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 + 2003-08-01 Havoc Pennington * dbus/dbus-object-registry.c (_dbus_object_registry_handle_and_unlock): 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" diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index a53be53d..0dd4fbc4 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -208,7 +208,8 @@ 3 - Error. + Error reply. If the first argument exists and is a + string, it is an error message. 4 @@ -231,10 +232,6 @@ 0x1 - This message is an error reply. If the first argument exists and is a string, it is an error message. - - - 0x2 This message does not expect method return replies or error replies; the reply can be omitted as an optimization. However, it is compliant with this specification -- cgit v1.2.1 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 --- ChangeLog | 9 + 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 +- 8 files changed, 637 insertions(+), 80 deletions(-) diff --git a/ChangeLog b/ChangeLog index a5051388..850906cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +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 + 2003-08-02 Havoc Pennington * dbus/dbus-message.c (dbus_message_get_no_reply) 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 v1.2.1 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 --- ChangeLog | 22 +++++++++ bus/activation.c | 4 +- bus/connection.c | 20 ++++----- bus/dispatch.c | 36 +++++++-------- bus/driver.c | 29 ++++++------ bus/test.c | 11 ++--- configure.in | 1 + dbus/dbus-connection.c | 1 + dbus/dbus-message.c | 106 +++++++++++++++++++++++++++++++++++++++++--- dbus/dbus-message.h | 5 +++ dbus/dbus-object-registry.c | 2 +- doc/dbus-specification.sgml | 1 - glib/test-dbus-glib.c | 4 +- glib/test-profile.c | 2 +- glib/test-thread-client.c | 2 +- glib/test-thread-server.c | 27 +++++------ test/decode-gcov.c | 4 ++ test/test-service.c | 16 +++---- tools/dbus-print-message.c | 23 +++++++++- tools/dbus-send.1 | 5 ++- tools/dbus-send.c | 46 +++++++++++++++++-- 21 files changed, 276 insertions(+), 91 deletions(-) diff --git a/ChangeLog b/ChangeLog index 850906cf..0473f388 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +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 + 2003-08-06 Havoc Pennington * dbus/dbus-object-registry.c: implement signal connection diff --git a/bus/activation.c b/bus/activation.c index a52fa4bc..91d3c116 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -586,7 +586,7 @@ bus_activation_service_created (BusActivation *activation, if (dbus_connection_get_is_connected (entry->connection)) { - message = dbus_message_new_reply (entry->activation_message); + message = dbus_message_new_method_return (entry->activation_message); if (!message) { BUS_SET_OOM (error); @@ -866,7 +866,7 @@ bus_activation_activate_service (BusActivation *activation, { _dbus_verbose ("Service \"%s\" is already active\n", service_name); - message = dbus_message_new_reply (activation_message); + message = dbus_message_new_method_return (activation_message); if (!message) { diff --git a/bus/connection.c b/bus/connection.c index 5121658d..e588039e 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -963,18 +963,18 @@ bus_connection_preallocate_oom_error (DBusConnection *connection) if (preallocated == NULL) return FALSE; - /* d->name may be NULL, but that is OK */ - message = dbus_message_new (DBUS_ERROR_NO_MEMORY, - d->name); + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); + if (message == NULL) { dbus_connection_free_preallocated_send (connection, preallocated); return FALSE; } - dbus_message_set_is_error (message, TRUE); - - if (!dbus_message_set_sender (message, + /* d->name may be NULL, but that is OK */ + if (!dbus_message_set_name (message, DBUS_ERROR_NO_MEMORY) || + !dbus_message_set_destination (message, d->name) || + !dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) { dbus_connection_free_preallocated_send (connection, preallocated); @@ -1338,7 +1338,7 @@ bus_transaction_send (BusTransaction *transaction, DBusList *link; _dbus_verbose (" trying to add %s %s to transaction%s\n", - dbus_message_get_is_error (message) ? "error" : + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" : dbus_message_get_reply_serial (message) != 0 ? "reply" : "message", dbus_message_get_name (message), @@ -1554,9 +1554,9 @@ bus_transaction_send_error_reply (BusTransaction *transaction, _dbus_verbose ("Sending error reply %s \"%s\"\n", error->name, error->message); - reply = dbus_message_new_error_reply (in_reply_to, - error->name, - error->message); + reply = dbus_message_new_error (in_reply_to, + error->name, + error->message); if (reply == NULL) return FALSE; diff --git a/bus/dispatch.c b/bus/dispatch.c index d43e8121..f4d19dcf 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -674,8 +674,8 @@ check_hello_message (BusContext *context, acquired = NULL; message = NULL; - message = dbus_message_new (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, + DBUS_SERVICE_DBUS); if (message == NULL) return TRUE; @@ -725,7 +725,7 @@ check_hello_message (BusContext *context, goto out; } - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { if (dbus_message_has_name (message, DBUS_ERROR_NO_MEMORY)) @@ -906,8 +906,8 @@ check_nonexistent_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + DBUS_SERVICE_DBUS); if (message == NULL) return TRUE; @@ -953,7 +953,7 @@ check_nonexistent_service_activation (BusContext *context, _dbus_verbose ("Received %s on %p\n", dbus_message_get_name (message), connection); - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { @@ -1287,8 +1287,8 @@ check_send_exit_to_service (BusContext *context, retval = FALSE; /* Kill off the test service by sending it a quit message */ - message = dbus_message_new ("org.freedesktop.DBus.TestSuiteExit", - service_name); + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteExit", + service_name); if (message == NULL) { @@ -1324,7 +1324,7 @@ check_send_exit_to_service (BusContext *context, /* see if we got an error during message bus dispatching */ bus_test_run_clients_loop (FALSE); message = dbus_connection_borrow_message (connection); - got_error = message != NULL && dbus_message_get_is_error (message); + got_error = message != NULL && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR; if (message) { dbus_connection_return_message (connection, message); @@ -1344,7 +1344,7 @@ check_send_exit_to_service (BusContext *context, message = pop_message_waiting_for_memory (connection); _dbus_assert (message != NULL); - if (!dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) { _dbus_warn ("expecting an error reply to asking test service to exit, got %s\n", dbus_message_get_name (message)); @@ -1402,7 +1402,7 @@ check_got_error (BusContext *context, goto out; } - if (!dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) { _dbus_warn ("Expected an error, got %s\n", dbus_message_get_name (message)); @@ -1460,8 +1460,8 @@ check_existent_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + DBUS_SERVICE_DBUS); if (message == NULL) return TRUE; @@ -1513,7 +1513,7 @@ check_existent_service_activation (BusContext *context, dbus_message_get_name (message), connection, DBUS_MESSAGE_ACTIVATE_SERVICE); - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { @@ -1563,7 +1563,7 @@ check_existent_service_activation (BusContext *context, } got_service_deleted = dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED); - got_error = dbus_message_get_is_error (message); + got_error = dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR; dbus_connection_return_message (connection, message); message = NULL; @@ -1668,8 +1668,8 @@ check_segfault_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + DBUS_SERVICE_DBUS); if (message == NULL) return TRUE; @@ -1716,7 +1716,7 @@ check_segfault_service_activation (BusContext *context, _dbus_verbose ("Received %s on %p\n", dbus_message_get_name (message), connection); - if (dbus_message_get_is_error (message)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) { diff --git a/bus/driver.c b/bus/driver.c index e0afd8ef..6e0024b0 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -49,8 +49,8 @@ bus_driver_send_service_deleted (const char *service_name, _dbus_verbose ("sending service deleted: %s\n", service_name); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_DELETED, - DBUS_SERVICE_BROADCAST); + message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_DELETED); + if (message == NULL) { BUS_SET_OOM (error); @@ -83,8 +83,8 @@ bus_driver_send_service_created (const char *service_name, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_CREATED, - DBUS_SERVICE_BROADCAST); + message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_CREATED); + if (message == NULL) { BUS_SET_OOM (error); @@ -123,15 +123,16 @@ bus_driver_send_service_lost (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_LOST, - bus_connection_get_name (connection)); + message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_LOST); + if (message == NULL) { BUS_SET_OOM (error); return FALSE; } - if (!dbus_message_append_args (message, + if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || + !dbus_message_append_args (message, DBUS_TYPE_STRING, service_name, DBUS_TYPE_INVALID)) { @@ -163,8 +164,7 @@ bus_driver_send_service_acquired (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_ACQUIRED, - bus_connection_get_name (connection)); + message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_ACQUIRED); if (message == NULL) { @@ -172,7 +172,8 @@ bus_driver_send_service_acquired (DBusConnection *connection, return FALSE; } - if (!dbus_message_append_args (message, + if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || + !dbus_message_append_args (message, DBUS_TYPE_STRING, service_name, DBUS_TYPE_INVALID)) { @@ -343,7 +344,7 @@ bus_driver_send_welcome_message (DBusConnection *connection, name = bus_connection_get_name (connection); _dbus_assert (name != NULL); - welcome = dbus_message_new_reply (hello_message); + welcome = dbus_message_new_method_return (hello_message); if (welcome == NULL) { BUS_SET_OOM (error); @@ -387,7 +388,7 @@ bus_driver_handle_list_services (DBusConnection *connection, registry = bus_connection_get_registry (connection); - reply = dbus_message_new_reply (message); + reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); @@ -463,7 +464,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection, error)) goto out; - reply = dbus_message_new_reply (message); + reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); @@ -518,7 +519,7 @@ bus_driver_handle_service_exists (DBusConnection *connection, _dbus_string_init_const (&service_name, name); service = bus_registry_lookup (registry, &service_name); - reply = dbus_message_new_reply (message); + reply = dbus_message_new_method_return (message); if (reply == NULL) { BUS_SET_OOM (error); diff --git a/bus/test.c b/bus/test.c index 30cbcd05..ca10422f 100644 --- a/bus/test.c +++ b/bus/test.c @@ -107,6 +107,10 @@ client_disconnect_handler (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { + if (!dbus_message_has_name (message, + DBUS_MESSAGE_LOCAL_DISCONNECT)) + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + _dbus_verbose ("Removing client %p in disconnect handler\n", connection); @@ -138,7 +142,6 @@ dbus_bool_t bus_setup_debug_client (DBusConnection *connection) { DBusMessageHandler *disconnect_handler; - const char *to_handle[] = { DBUS_MESSAGE_LOCAL_DISCONNECT }; dbus_bool_t retval; disconnect_handler = dbus_message_handler_new (client_disconnect_handler, @@ -147,10 +150,8 @@ bus_setup_debug_client (DBusConnection *connection) if (disconnect_handler == NULL) return FALSE; - if (!dbus_connection_register_handler (connection, - disconnect_handler, - to_handle, - _DBUS_N_ELEMENTS (to_handle))) + if (!dbus_connection_add_filter (connection, + disconnect_handler)) { dbus_message_handler_unref (disconnect_handler); return FALSE; diff --git a/configure.in b/configure.in index f8e69caf..3963a5de 100644 --- a/configure.in +++ b/configure.in @@ -844,6 +844,7 @@ echo " cflags: ${CFLAGS} cppflags: ${CPPFLAGS} cxxflags: ${CXXFLAGS} + 64-bit int: ${DBUS_INT64_TYPE} Doxygen: ${DOXYGEN} db2html: ${DB2HTML}" 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); diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index 0dd4fbc4..6c6f679a 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -201,7 +201,6 @@ 1 Method call. - 2 Method reply with returned data. diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c index d963ee3d..d4b5f9b2 100644 --- a/glib/test-dbus-glib.c +++ b/glib/test-dbus-glib.c @@ -30,8 +30,8 @@ main (int argc, char **argv) dbus_connection_setup_with_g_main (connection, NULL); - message = dbus_message_new (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, + DBUS_SERVICE_DBUS); dbus_error_init (&error); reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); diff --git a/glib/test-profile.c b/glib/test-profile.c index f213c676..6d13e32f 100644 --- a/glib/test-profile.c +++ b/glib/test-profile.c @@ -38,7 +38,7 @@ send_echo_message (DBusConnection *connection) { DBusMessage *message; - message = dbus_message_new (ECHO_MESSAGE, NULL); + message = dbus_message_new_method_call (ECHO_MESSAGE, NULL); dbus_message_append_args (message, DBUS_TYPE_STRING, "Hello World!", DBUS_TYPE_INT32, 123456, diff --git a/glib/test-thread-client.c b/glib/test-thread-client.c index 02ebdf67..a3290b27 100644 --- a/glib/test-thread-client.c +++ b/glib/test-thread-client.c @@ -19,7 +19,7 @@ thread_func (gpointer data) while (1) { - message = dbus_message_new ("org.freedesktop.ThreadTest", NULL); + message = dbus_message_new_method_call ("org.freedesktop.ThreadTest", NULL); dbus_message_append_iter_init (message, &iter); diff --git a/glib/test-thread-server.c b/glib/test-thread-server.c index 00044a79..4cc886fd 100644 --- a/glib/test-thread-server.c +++ b/glib/test-thread-server.c @@ -42,6 +42,9 @@ handle_test_message (DBusMessageHandler *handler, char *str, *expected_str; GString *counter_str; int i; + + if (!dbus_message_has_name (message, "org.freedesktop.ThreadTest")) + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; dbus_message_iter_init (message, &iter); @@ -124,7 +127,7 @@ handle_test_message (DBusMessageHandler *handler, g_string_free (counter_str, TRUE); out: - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; } static DBusHandlerResult @@ -132,7 +135,7 @@ handle_filter (DBusMessageHandler *handler, DBusConnection *connection, DBusMessage *message, void *user_data) -{ +{ return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } @@ -142,20 +145,20 @@ handle_disconnect (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { + if (!dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + g_print ("connection disconnected\n"); dbus_connection_unref (connection); - - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; } - static void new_connection_callback (DBusServer *server, DBusConnection *new_connection, void *user_data) { - const char *test_messages[] = { "org.freedesktop.ThreadTest" }; - const char *disconnect_messages[] = { "org.freedesktop.Local.Disconnect" }; DBusMessageHandler *test_message_handler; ThreadTestData * data; @@ -170,9 +173,8 @@ new_connection_callback (DBusServer *server, dbus_message_handler_new (handle_test_message, data, (DBusFreeFunction)thread_test_data_free); - if (!dbus_connection_register_handler (new_connection, - test_message_handler, - test_messages, 1)) + if (!dbus_connection_add_filter (new_connection, + test_message_handler)) goto nomem; if (!dbus_connection_set_data (new_connection, @@ -181,9 +183,8 @@ new_connection_callback (DBusServer *server, (DBusFreeFunction)dbus_message_handler_unref)) goto nomem; - if (!dbus_connection_register_handler (new_connection, - disconnect_handler, - disconnect_messages, 1)) + if (!dbus_connection_add_filter (new_connection, + disconnect_handler)) goto nomem; if (!dbus_connection_add_filter (new_connection, diff --git a/test/decode-gcov.c b/test/decode-gcov.c index d13340e3..a7a4478b 100644 --- a/test/decode-gcov.c +++ b/test/decode-gcov.c @@ -38,6 +38,10 @@ #include #include +#ifndef DBUS_HAVE_INT64 +#error "gcov support can't be built without 64-bit integer support" +#endif + static void die (const char *message) { diff --git a/test/test-service.c b/test/test-service.c index c2757acc..0771f33c 100644 --- a/test/test-service.c +++ b/test/test-service.c @@ -37,9 +37,9 @@ handle_echo (DBusConnection *connection, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) { - reply = dbus_message_new_error_reply (message, - error.name, - error.message); + reply = dbus_message_new_error (message, + error.name, + error.message); if (reply == NULL) die ("No memory\n"); @@ -52,7 +52,7 @@ handle_echo (DBusConnection *connection, return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } - reply = dbus_message_new_reply (message); + reply = dbus_message_new_method_return (message); if (reply == NULL) die ("No memory\n"); @@ -99,11 +99,6 @@ main (int argc, DBusConnection *connection; DBusError error; DBusMessageHandler *handler; - const char *to_handle[] = { - "org.freedesktop.DBus.TestSuiteEcho", - "org.freedesktop.DBus.TestSuiteExit", - DBUS_MESSAGE_LOCAL_DISCONNECT, - }; int result; dbus_error_init (&error); @@ -127,8 +122,7 @@ main (int argc, if (handler == NULL) die ("No memory"); - if (!dbus_connection_register_handler (connection, handler, to_handle, - _DBUS_N_ELEMENTS (to_handle))) + if (!dbus_connection_add_filter (connection, handler)) die ("No memory"); result = dbus_bus_acquire_service (connection, "org.freedesktop.DBus.TestSuiteEchoService", diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c index bb380ce5..7c5328da 100644 --- a/tools/dbus-print-message.c +++ b/tools/dbus-print-message.c @@ -21,15 +21,36 @@ */ #include "dbus-print-message.h" +static const char* +type_to_name (int message_type) +{ + switch (message_type) + { + case DBUS_MESSAGE_TYPE_SIGNAL: + return "signal"; + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return "method call"; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + return "method return"; + case DBUS_MESSAGE_TYPE_ERROR: + return "error"; + default: + return "(unknown message type)"; + } +} + void print_message (DBusMessage *message) { DBusMessageIter iter; const char *sender; + int message_type; + message_type = dbus_message_get_type (message); sender = dbus_message_get_sender (message); - printf ("message name=%s; sender=%s\n", + printf ("%s name=%s; sender=%s\n", + type_to_name (message_type), dbus_message_get_name (message), sender ? sender : "(no sender)"); diff --git a/tools/dbus-send.1 b/tools/dbus-send.1 index 08ea1335..f71c4c6e 100644 --- a/tools/dbus-send.1 +++ b/tools/dbus-send.1 @@ -8,7 +8,7 @@ dbus-send \- Send a message to a message bus .SH SYNOPSIS .PP .B dbus-send -[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply] [contents ...] +[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply] [\-\-type=TYPE] [contents ...] .SH DESCRIPTION @@ -62,6 +62,9 @@ Send to the system message bus. .TP .I "--session" Send to the session message bus. (This is the default.) +.TP +.I "--type=TYPE" +Specify "method_call" or "signal" (defaults to "signal"). .SH AUTHOR dbus-send was written by Philip Blundell. diff --git a/tools/dbus-send.c b/tools/dbus-send.c index 12ad5c8c..fb876b52 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -30,7 +30,7 @@ static void usage (char *name, int ecode) { - fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--print-reply] [contents ...]\n", name); + fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--type=TYPE] [--print-reply] [contents ...]\n", name); exit (ecode); } @@ -44,9 +44,11 @@ main (int argc, char *argv[]) DBusMessageIter iter; int i; DBusBusType type = DBUS_BUS_SESSION; - char *dest = DBUS_SERVICE_BROADCAST; + const char *dest = DBUS_SERVICE_BROADCAST; char *name = NULL; - + int message_type = DBUS_MESSAGE_TYPE_SIGNAL; + const char *type_str = NULL; + if (argc < 2) usage (argv[0], 1); @@ -64,6 +66,8 @@ main (int argc, char *argv[]) print_reply = TRUE; else if (strstr (arg, "--dest=") == arg) dest = strchr (arg, '=') + 1; + else if (strstr (arg, "--type=") == arg) + type_str = strchr (arg, '=') + 1; else if (!strcmp(arg, "--help")) usage (argv[0], 0); else if (arg[0] == '-') @@ -75,6 +79,20 @@ main (int argc, char *argv[]) if (name == NULL) usage (argv[0], 1); + if (type_str != NULL) + { + if (strcmp (type_str, "method_call") == 0) + message_type = DBUS_MESSAGE_TYPE_METHOD_CALL; + else if (strcmp (type_str, "signal") == 0) + message_type = DBUS_MESSAGE_TYPE_SIGNAL; + else + { + fprintf (stderr, "Message type \"%s\" is not supported\n", + type_str); + exit (1); + } + } + dbus_error_init (&error); connection = dbus_bus_get (type, &error); if (connection == NULL) @@ -86,13 +104,32 @@ main (int argc, char *argv[]) exit (1); } - message = dbus_message_new (name, dest); + if (message_type == DBUS_MESSAGE_TYPE_METHOD_CALL) + { + message = dbus_message_new_method_call (name, NULL); + } + else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL) + { + message = dbus_message_new_signal (name); + } + else + { + fprintf (stderr, "Internal error, unknown message type\n"); + exit (1); + } + if (message == NULL) { fprintf (stderr, "Couldn't allocate D-BUS message\n"); exit (1); } + if (dest && !dbus_message_set_destination (message, dest)) + { + fprintf (stderr, "Not enough memory\n"); + exit (1); + } + dbus_message_append_iter_init (message, &iter); while (i < argc) @@ -135,6 +172,7 @@ main (int argc, char *argv[]) exit (1); } + /* FIXME - we are ignoring OOM returns on all these functions */ switch (type) { case DBUS_TYPE_BYTE: -- cgit v1.2.1 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. --- ChangeLog | 10 ++++++++++ bus/dispatch.c | 2 +- bus/test.c | 4 ++-- dbus/dbus-connection.c | 10 +++++----- dbus/dbus-message-handler.c | 4 ++-- dbus/dbus-object-registry.c | 24 ++++++++++++++---------- dbus/dbus-object.h | 4 ++-- glib/test-profile.c | 6 ++++-- glib/test-thread-server.c | 10 +++++----- test/test-service.c | 8 ++++---- tools/dbus-monitor.c | 2 +- 11 files changed, 50 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0473f388..b786b4ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +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. + 2003-08-10 Havoc Pennington * tools/dbus-send.c (main): add --type argument, for now diff --git a/bus/dispatch.c b/bus/dispatch.c index f4d19dcf..6902da65 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -305,7 +305,7 @@ bus_dispatch_message_handler (DBusMessageHandler *handler, { bus_dispatch (connection, message); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void diff --git a/bus/test.c b/bus/test.c index ca10422f..d28d7edf 100644 --- a/bus/test.c +++ b/bus/test.c @@ -109,7 +109,7 @@ client_disconnect_handler (DBusMessageHandler *handler, { if (!dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; _dbus_verbose ("Removing client %p in disconnect handler\n", connection); @@ -124,7 +124,7 @@ client_disconnect_handler (DBusMessageHandler *handler, client_loop = NULL; } - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_HANDLED; } static dbus_int32_t handler_slot = -1; 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; diff --git a/glib/test-profile.c b/glib/test-profile.c index 6d13e32f..852bd091 100644 --- a/glib/test-profile.c +++ b/glib/test-profile.c @@ -76,9 +76,10 @@ client_filter (DBusMessageHandler *handler, exit (0); } send_echo_message (connection); + return DBUS_HANDLER_RESULT_HANDLED; } - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void* @@ -147,9 +148,10 @@ server_filter (DBusMessageHandler *handler, ECHO_MESSAGE)) { send_echo_message (connection); + return DBUS_HANDLER_RESULT_HANDLED; } - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void diff --git a/glib/test-thread-server.c b/glib/test-thread-server.c index 4cc886fd..3ad1f907 100644 --- a/glib/test-thread-server.c +++ b/glib/test-thread-server.c @@ -44,7 +44,7 @@ handle_test_message (DBusMessageHandler *handler, int i; if (!dbus_message_has_name (message, "org.freedesktop.ThreadTest")) - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; dbus_message_iter_init (message, &iter); @@ -127,7 +127,7 @@ handle_test_message (DBusMessageHandler *handler, g_string_free (counter_str, TRUE); out: - return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult @@ -136,7 +136,7 @@ handle_filter (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult @@ -146,12 +146,12 @@ handle_disconnect (DBusMessageHandler *handler, void *user_data) { if (!dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; g_print ("connection disconnected\n"); dbus_connection_unref (connection); - return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; + return DBUS_HANDLER_RESULT_HANDLED; } static void diff --git a/test/test-service.c b/test/test-service.c index 0771f33c..fffe4187 100644 --- a/test/test-service.c +++ b/test/test-service.c @@ -49,7 +49,7 @@ handle_echo (DBusConnection *connection, dbus_message_unref (reply); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } reply = dbus_message_new_method_return (message); @@ -68,7 +68,7 @@ handle_echo (DBusConnection *connection, dbus_message_unref (reply); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult @@ -84,11 +84,11 @@ filter_func (DBusMessageHandler *handler, { dbus_connection_disconnect (connection); quit (); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_HANDLED; } else { - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } } diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c index dac15292..a0f77407 100644 --- a/tools/dbus-monitor.c +++ b/tools/dbus-monitor.c @@ -40,7 +40,7 @@ handler_func (DBusMessageHandler *handler, if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) exit (0); - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void -- cgit v1.2.1 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. --- ChangeLog | 18 ++++++++ bus/dispatch.c | 12 +++-- bus/driver.c | 2 +- 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 +- 13 files changed, 227 insertions(+), 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index b786b4ec..4396c9a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +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. + 2003-08-11 Havoc Pennington * bus/test.c (client_disconnect_handler): change to return diff --git a/bus/dispatch.c b/bus/dispatch.c index 6902da65..e8f0c9ba 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -100,7 +100,7 @@ bus_dispatch_broadcast_message (BusTransaction *transaction, return TRUE; } -static void +static DBusHandlerResult bus_dispatch (DBusConnection *connection, DBusMessage *message) { @@ -108,6 +108,9 @@ bus_dispatch (DBusConnection *connection, DBusError error; BusTransaction *transaction; BusContext *context; + DBusHandlerResult result; + + result = DBUS_HANDLER_RESULT_HANDLED; transaction = NULL; dbus_error_init (&error); @@ -145,6 +148,7 @@ bus_dispatch (DBusConnection *connection, /* DBusConnection also handles some of these automatically, we leave * it to do so. */ + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; goto out; } @@ -295,6 +299,8 @@ bus_dispatch (DBusConnection *connection, } dbus_connection_unref (connection); + + return result; } static DBusHandlerResult @@ -303,9 +309,7 @@ bus_dispatch_message_handler (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - bus_dispatch (connection, message); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return bus_dispatch (connection, message); } static void diff --git a/bus/driver.c b/bus/driver.c index 6e0024b0..22e36e0a 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -662,7 +662,7 @@ bus_driver_handle_message (DBusConnection *connection, _dbus_verbose ("No driver handler for %s\n", name); - dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE, + dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD, "%s does not understand message %s", DBUS_SERVICE_DBUS, name); 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 v1.2.1 From 9d1c3a0f8428f4b052899ab12c706961efb003d4 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 13 Aug 2003 22:14:47 +0000 Subject: new file, just fooling around --- glib/dbus-gidl.h | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 glib/dbus-gidl.h diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h new file mode 100644 index 00000000..a5dc6cb0 --- /dev/null +++ b/glib/dbus-gidl.h @@ -0,0 +1,80 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gidl.h data structure describing an interface, to be generated from IDL + * or something + * + * 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_GLIB_IDL_H +#define DBUS_GLIB_IDL_H + +#include +#include + +G_BEGIN_DECLS + +typedef struct InterfaceInfo InterfaceInfo; +typedef struct MethodInfo MethodInfo; +typedef struct SignalInfo SignalInfo; +typedef struct ArgInfo ArgInfo; + +typedef enum +{ + ARG_IN, + ARG_OUT +} ArgDirection; + +typedef enum +{ + METHOD_SYNC, + METHOD_ASYNC, + METHOD_CANCELLABLE +} MethodStyle; + +InterfaceInfo* interface_info_new (void); +void interface_info_ref (InterfaceInfo *info); +void interface_info_unref (InterfaceInfo *info); +GSList* interface_info_get_methods (InterfaceInfo *info); +GSList* interface_info_get_signals (InterfaceInfo *info); + +MethodInfo* method_info_new (void); +void method_info_ref (MethodInfo *info); +void method_info_unref (MethodInfo *info); + +const char* method_info_get_name (MethodInfo *info); +GSList* method_info_get_args (MethodInfo *info); +MethodStyle method_info_get_style (MethodInfo *info); + +SignalInfo* signal_info_new (void); +void signal_info_ref (SignalInfo *info); +void signal_info_unref (SignalInfo *info); + +const char* signal_info_get_name (SignalInfo *info); +GSList* signal_info_get_args (SignalInfo *info); + +ArgInfo* arg_info_new (void); +void arg_info_ref (ArgInfo *info); +void arg_info_unref (ArgInfo *info); +const char* arg_info_get_name (ArgInfo *info); +int arg_info_get_type (ArgInfo *info); +ArgDirection arg_info_get_direction (ArgInfo *info); + +G_END_DECLS + +#endif /* DBUS_GLIB_IDL_H */ -- cgit v1.2.1 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 --- ChangeLog | 11 ++ dbus/dbus-pending-call.c | 225 +++++++++++++++++++++++++++++++ dbus/dbus-pending-call.h | 55 ++++++++ glib/Makefile.am | 15 ++- glib/dbus-compiler-main.c | 48 +++++++ glib/dbus-gidl.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++ glib/dbus-gidl.h | 19 ++- glib/dbus-glib.h | 4 + glib/dbus-gproxy.c | 170 ++++++++++++++++++++++++ glib/dbus-gproxy.h | 79 +++++++++++ 10 files changed, 951 insertions(+), 6 deletions(-) create mode 100644 dbus/dbus-pending-call.c create mode 100644 dbus/dbus-pending-call.h create mode 100644 glib/dbus-compiler-main.c create mode 100644 glib/dbus-gidl.c create mode 100644 glib/dbus-gproxy.c create mode 100644 glib/dbus-gproxy.h diff --git a/ChangeLog b/ChangeLog index 4396c9a5..e379f432 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +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 + 2003-08-12 Havoc Pennington * bus/dispatch.c (bus_dispatch): make this return proper 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 */ diff --git a/glib/Makefile.am b/glib/Makefile.am index ebdb932f..8cc09eb7 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -1,18 +1,29 @@ -INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION=1 dbusincludedir=$(includedir)/dbus-1.0/dbus lib_LTLIBRARIES=libdbus-glib-1.la dbusinclude_HEADERS= \ - dbus-glib.h + dbus-glib.h \ + dbus-gproxy.h libdbus_glib_1_la_SOURCES = \ dbus-gmain.c \ + dbus-gproxy.c \ dbus-gthread.c libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la +bin_PROGRAMS=dbus-glib-compiler + +dbus_glib_compiler_SOURCES = \ + dbus-gidl.c \ + dbus-gidl.h \ + dbus-compiler-main.c + +dbus_glib_compiler_LDADD= libdbus-glib-1.la $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la + if DBUS_BUILD_TESTS if HAVE_GLIB_THREADS diff --git a/glib/dbus-compiler-main.c b/glib/dbus-compiler-main.c new file mode 100644 index 00000000..d8bf7bde --- /dev/null +++ b/glib/dbus-compiler-main.c @@ -0,0 +1,48 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-compiler-main.c main() for GLib stubs/skels generator + * + * 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-gidl.h" + +int +main (int argc, char **argv) +{ + + + return 0; +} + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGCompiler + * Unit test for GLib stubs/skels compiler + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gcompiler_test (void) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c new file mode 100644 index 00000000..b6e0fb8c --- /dev/null +++ b/glib/dbus-gidl.c @@ -0,0 +1,331 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gidl.c data structure describing an interface, to be generated from IDL + * or something + * + * 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-gidl.h" + +struct InterfaceInfo +{ + int refcount; + char *name; + GSList *methods; + GSList *signals; +}; + +struct MethodInfo +{ + int refcount; + GSList *args; + char *name; + MethodStyle style; +}; + +struct SignalInfo +{ + int refcount; + GSList *args; + char *name; +}; + +struct ArgInfo +{ + int refcount; + char *name; + int type; + ArgDirection direction; +}; + +static void +free_method_list (GSList **methods_p) +{ + GSList *tmp; + tmp = *methods_p; + while (tmp != NULL) + { + method_info_unref (tmp->data); + tmp = tmp->next; + } + g_slist_free (*methods_p); + *methods_p = NULL; +} + +static void +free_signal_list (GSList **signals_p) +{ + GSList *tmp; + tmp = *signals_p; + while (tmp != NULL) + { + signal_info_unref (tmp->data); + tmp = tmp->next; + } + g_slist_free (*signals_p); + *signals_p = NULL; +} + +InterfaceInfo* +interface_info_new (const char *name) +{ + InterfaceInfo *info; + + info = g_new0 (InterfaceInfo, 1); + info->refcount = 1; + info->name = g_strdup (name); + + return info; +} + +void +interface_info_ref (InterfaceInfo *info) +{ + info->refcount += 1; +} + +void +interface_info_unref (InterfaceInfo *info) +{ + info->refcount -= 1; + if (info->refcount == 0) + { + free_method_list (&info->methods); + free_signal_list (&info->signals); + g_free (info->name); + g_free (info); + } +} + +GSList* +interface_info_get_methods (InterfaceInfo *info) +{ + return info->methods; +} + +GSList* +interface_info_get_signals (InterfaceInfo *info) +{ + return info->signals; +} + +void +interface_info_add_method (InterfaceInfo *info, + MethodInfo *method) +{ + method_info_ref (method); + info->methods = g_slist_append (info->methods, method); +} + +void +interface_info_add_signal (InterfaceInfo *info, + SignalInfo *signal) +{ + signal_info_ref (signal); + info->signals = g_slist_append (info->signals, signal); +} + +static void +free_arg_list (GSList **args_p) +{ + GSList *tmp; + tmp = *args_p; + while (tmp != NULL) + { + arg_info_unref (tmp->data); + tmp = tmp->next; + } + g_slist_free (*args_p); + *args_p = NULL; +} + +MethodInfo* +method_info_new (const char *name, + MethodStyle style) +{ + MethodInfo *info; + + info = g_new0 (MethodInfo, 1); + info->refcount = 1; + info->name = g_strdup (name); + info->style = style; + + return info; +} + +void +method_info_ref (MethodInfo *info) +{ + info->refcount += 1; +} + +void +method_info_unref (MethodInfo *info) +{ + info->refcount -= 1; + if (info->refcount == 0) + { + free_arg_list (&info->args); + g_free (info->name); + g_free (info); + } +} + +const char* +method_info_get_name (MethodInfo *info) +{ + return info->name; +} + +GSList* +method_info_get_args (MethodInfo *info) +{ + return info->args; +} + +MethodStyle +method_info_get_style (MethodInfo *info) +{ + return info->style; +} + +void +method_info_add_arg (MethodInfo *info, + ArgInfo *arg) +{ + arg_info_ref (arg); + info->args = g_slist_append (info->args, arg); +} + +SignalInfo* +signal_info_new (const char *name) +{ + SignalInfo *info; + + info = g_new0 (SignalInfo, 1); + info->refcount = 1; + info->name = g_strdup (name); + + return info; +} + +void +signal_info_ref (SignalInfo *info) +{ + info->refcount += 1; +} + +void +signal_info_unref (SignalInfo *info) +{ + info->refcount -= 1; + if (info->refcount == 0) + { + free_arg_list (&info->args); + g_free (info->name); + g_free (info); + } +} + +const char* +signal_info_get_name (SignalInfo *info) +{ + return info->name; +} + +GSList* +signal_info_get_args (SignalInfo *info) +{ + return info->args; +} + +void +signal_info_add_arg (SignalInfo *info, + ArgInfo *arg) +{ + arg_info_ref (arg); + info->args = g_slist_append (info->args, arg); +} + +ArgInfo* +arg_info_new (const char *name, + ArgDirection direction, + int type) +{ + ArgInfo *info; + + info = g_new0 (ArgInfo, 1); + info->refcount = 1; + info->name = g_strdup (name); + info->direction = direction; + info->type = type; + + return info; +} + +void +arg_info_ref (ArgInfo *info) +{ + info->refcount += 1; +} + +void +arg_info_unref (ArgInfo *info) +{ + info->refcount -= 1; + if (info->refcount == 0) + { + g_free (info->name); + g_free (info); + } +} +const char* +arg_info_get_name (ArgInfo *info) +{ + return info->name; +} + +int +arg_info_get_type (ArgInfo *info) +{ + return info->type; +} + +ArgDirection +arg_info_get_direction (ArgInfo *info) +{ + return info->direction; +} + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGIDL + * Unit test for GLib IDL internals + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gidl_test (void) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index a5dc6cb0..c3c72d61 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -47,28 +47,39 @@ typedef enum METHOD_CANCELLABLE } MethodStyle; -InterfaceInfo* interface_info_new (void); +InterfaceInfo* interface_info_new (const char *name); void interface_info_ref (InterfaceInfo *info); void interface_info_unref (InterfaceInfo *info); GSList* interface_info_get_methods (InterfaceInfo *info); GSList* interface_info_get_signals (InterfaceInfo *info); +void interface_info_add_method (InterfaceInfo *info, + MethodInfo *method); +void interface_info_add_signal (InterfaceInfo *info, + SignalInfo *signal); -MethodInfo* method_info_new (void); +MethodInfo* method_info_new (const char *name, + MethodStyle style); void method_info_ref (MethodInfo *info); void method_info_unref (MethodInfo *info); const char* method_info_get_name (MethodInfo *info); GSList* method_info_get_args (MethodInfo *info); MethodStyle method_info_get_style (MethodInfo *info); +void method_info_add_arg (MethodInfo *info, + ArgInfo *arg); -SignalInfo* signal_info_new (void); +SignalInfo* signal_info_new (const char *name); void signal_info_ref (SignalInfo *info); void signal_info_unref (SignalInfo *info); const char* signal_info_get_name (SignalInfo *info); GSList* signal_info_get_args (SignalInfo *info); +void signal_info_add_arg (SignalInfo *info, + ArgInfo *arg); -ArgInfo* arg_info_new (void); +ArgInfo* arg_info_new (const char *name, + ArgDirection direction, + int type); void arg_info_ref (ArgInfo *info); void arg_info_unref (ArgInfo *info); const char* arg_info_get_name (ArgInfo *info); diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index c6116c52..7ca22417 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -28,12 +28,16 @@ G_BEGIN_DECLS +#define DBUS_INSIDE_DBUS_GLIB_H 1 + void dbus_gthread_init (void); void dbus_connection_setup_with_g_main (DBusConnection *connection, GMainContext *context); void dbus_server_setup_with_g_main (DBusServer *server, GMainContext *context); +#undef DBUS_INSIDE_DBUS_GLIB_H + G_END_DECLS #endif /* DBUS_GLIB_H */ diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c new file mode 100644 index 00000000..4326057a --- /dev/null +++ b/glib/dbus-gproxy.c @@ -0,0 +1,170 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gcall.c convenience routines for calling methods, etc. + * + * 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-gproxy.h" + +/** + * @addtogroup DBusGLibInternals + * + * @{ + */ + +struct DBusGProxy +{ + int refcount; + DBusConnection *connection; + char *service; + char *interface; + DBusObjectID object_id; +}; + +static DBusGProxy* +_dbus_gproxy_new (DBusConnection *connection) +{ + DBusGProxy *proxy; + + proxy = g_new0 (DBusGProxy, 1); + + proxy->refcount = 1; + proxy->connection = connection; + dbus_connection_ref (connection); + + return proxy; +} + +/** @} End of DBusGLibInternals */ + +/** @addtogroup DBusGLib + * @{ + */ + +/** + * Creates a new proxy for a remote interface. Method calls and signal + * connections over this proxy will go to the service owner; the + * service owner is expected to support the given interface name. THE + * SERVICE OWNER MAY CHANGE OVER TIME, for example between two + * different method calls. If you need a fixed owner, you need to + * request the current owner and bind a proxy to that rather than to + * the generic service name; see dbus_gproxy_new_for_service_owner(). + * + * A service-associated proxy only makes sense with a message bus, + * not for app-to-app direct dbus connections. + * + * @param connection the connection to the remote bus or app + * @param service_name name of the service on the message bus + * @param interface_name name of the interface to call methods on + * @returns new proxy object + */ +DBusGProxy* +dbus_gproxy_new_for_service (DBusConnection *connection, + const char *service_name, + const char *interface_name) +{ + DBusGProxy *proxy; + + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (interface_name != NULL, NULL); + + proxy = _dbus_gproxy_new (connection); + + proxy->service = g_strdup (service_name); + proxy->interface = g_strdup (interface_name); + + return proxy; +} + +/** + * Increment reference count on proxy object. + * + * @param proxy the proxy + */ +void +dbus_gproxy_ref (DBusGProxy *proxy) +{ + g_return_if_fail (proxy != NULL); + + proxy->refcount += 1; +} + +/** + * Decrement reference count on proxy object. + * + * @param proxy the proxy + */ +void +dbus_gproxy_unref (DBusGProxy *proxy) +{ + g_return_if_fail (proxy != NULL); + + proxy->refcount -= 1; + if (proxy->refcount == 0) + { + dbus_connection_unref (proxy->connection); + g_free (proxy->interface); + g_free (proxy->service); + g_free (proxy); + } +} + +/** + * Invokes a method on a remote interface. This function does not + * block; instead it returns an opaque #DBusGPendingCall object that + * tracks the pending call. The method call will not be sent over the + * wire until the application returns to the main loop, or blocks in + * dbus_connection_flush() to write out pending data. The call will + * be completed after a timeout, or when a reply is received. + * + * @param proxy a proxy for a remote interface + * @param method the name of the method to invoke + * @param first_arg_type type of the first argument + * + * @returns opaque pending call object + * + */ +DBusGPendingCall* +dbus_gproxy_begin_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...) +{ + + +} + +/** @} End of DBusGLib public */ + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGLibInternals + * Unit test for GLib proxy functions + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gproxy_test (void) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gproxy.h b/glib/dbus-gproxy.h new file mode 100644 index 00000000..bebcd1ce --- /dev/null +++ b/glib/dbus-gproxy.h @@ -0,0 +1,79 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gproxy.h convenience routines for calling methods, etc. + * + * 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_GPROXY_H +#define DBUS_GPROXY_H + +#if !defined (DBUS_INSIDE_DBUS_GLIB_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#include +#include +#include /* for GCallback at the moment, we don't link to it */ + +G_BEGIN_DECLS + +typedef struct DBusGProxy DBusGProxy; +typedef struct DBusGPendingCall DBusGPendingCall; + +DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, + const char *service_name, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, + const char *service_name, + const char *interface_name, + GError **error); +DBusGProxy* dbus_gproxy_new_for_object_id (DBusConnection *connection, + const DBusObjectID *object_id, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, + const char *interface_name); +void dbus_gproxy_ref (DBusGProxy *proxy); +void dbus_gproxy_unref (DBusGProxy *proxy); +gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *signal_name, + GCallback callback, + void *data, + GFreeFunc free_data_func, + GError **error); +DBusGPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); +void dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); + +gboolean dbus_gpending_call_is_complete (DBusGPendingCall *call); +void dbus_gpending_call_cancel_and_free (DBusGPendingCall *call); +gboolean dbus_gpending_call_block_and_free (DBusGPendingCall *call, + GError **error, + int first_arg_type, + ...); + + + +G_END_DECLS + +#endif /* DBUS_GPROXY_H */ -- cgit v1.2.1 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 --- ChangeLog | 5 + 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 + 10 files changed, 363 insertions(+), 223 deletions(-) diff --git a/ChangeLog b/ChangeLog index e379f432..f1024dbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-08-15 Havoc Pennington + + * dbus/dbus-connection.c, + dbus/dbus-pending-call.c: Finish the pending call stuff + 2003-08-14 Havoc Pennington * dbus/dbus-pending-call.c: start on new object that will replace 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 v1.2.1 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 --- ChangeLog | 9 +++ dbus/dbus-connection-internal.h | 9 ++- dbus/dbus-connection.c | 161 ++++++++++++++++++++++++++++------------ dbus/dbus-pending-call.c | 25 +++++++ dbus/dbus-pending-call.h | 1 + glib/dbus-gproxy.h | 70 ++++++++--------- 6 files changed, 191 insertions(+), 84 deletions(-) diff --git a/ChangeLog b/ChangeLog index f1024dbb..4a8f4ac6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +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 + 2003-08-15 Havoc Pennington * dbus/dbus-connection.c, 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; diff --git a/glib/dbus-gproxy.h b/glib/dbus-gproxy.h index bebcd1ce..47b70f36 100644 --- a/glib/dbus-gproxy.h +++ b/glib/dbus-gproxy.h @@ -34,43 +34,43 @@ G_BEGIN_DECLS typedef struct DBusGProxy DBusGProxy; -typedef struct DBusGPendingCall DBusGPendingCall; +typedef struct DBusPendingCall DBusPendingCall; -DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, - const char *service_name, - const char *interface_name); -DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, - const char *service_name, - const char *interface_name, - GError **error); -DBusGProxy* dbus_gproxy_new_for_object_id (DBusConnection *connection, - const DBusObjectID *object_id, - const char *interface_name); -DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, - const char *interface_name); -void dbus_gproxy_ref (DBusGProxy *proxy); -void dbus_gproxy_unref (DBusGProxy *proxy); -gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, - const char *signal_name, - GCallback callback, - void *data, - GFreeFunc free_data_func, - GError **error); -DBusGPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, - ...); -void dbus_gproxy_oneway_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, - ...); +DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, + const char *service_name, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, + const char *service_name, + const char *interface_name, + GError **error); +DBusGProxy* dbus_gproxy_new_for_object_id (DBusConnection *connection, + const DBusObjectID *object_id, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, + const char *interface_name); +void dbus_gproxy_ref (DBusGProxy *proxy); +void dbus_gproxy_unref (DBusGProxy *proxy); +gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *signal_name, + GCallback callback, + void *data, + GFreeFunc free_data_func, + GError **error); +DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); +void dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); +gboolean dbus_pending_call_is_complete (DBusPendingCall *call); +void dbus_pending_call_cancel_and_free (DBusPendingCall *call); +gboolean dbus_pending_call_block_and_free (DBusPendingCall *call, + GError **error, + int first_arg_type, + ...); -gboolean dbus_gpending_call_is_complete (DBusGPendingCall *call); -void dbus_gpending_call_cancel_and_free (DBusGPendingCall *call); -gboolean dbus_gpending_call_block_and_free (DBusGPendingCall *call, - GError **error, - int first_arg_type, - ...); -- cgit v1.2.1 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 --- ChangeLog | 7 +++ dbus/dbus-message.c | 4 ++ dbus/dbus-object-registry.c | 1 - glib/dbus-gproxy.c | 118 ++++++++++++++++++++++++++++++++++++++++++-- glib/dbus-gproxy.h | 17 +++---- 5 files changed, 132 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4a8f4ac6..b2f71f14 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-08-16 Havoc Pennington + + * dbus/dbus-object-registry.c (add_and_remove_objects): remove + broken assertion + + * glib/dbus-gproxy.c: some hacking + 2003-08-15 Havoc Pennington * dbus/dbus-pending-call.c (dbus_pending_call_block): implement 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, diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 4326057a..36f9724c 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -30,6 +30,7 @@ struct DBusGProxy { + GStaticMutex lock; int refcount; DBusConnection *connection; char *service; @@ -37,17 +38,22 @@ struct DBusGProxy DBusObjectID object_id; }; +#define LOCK_PROXY(proxy) (g_static_mutex_lock (&(proxy)->lock)) +#define UNLOCK_PROXY(proxy) (g_static_mutex_unlock (&(proxy)->lock)) + static DBusGProxy* _dbus_gproxy_new (DBusConnection *connection) { DBusGProxy *proxy; proxy = g_new0 (DBusGProxy, 1); - + proxy->refcount = 1; proxy->connection = connection; dbus_connection_ref (connection); + g_static_mutex_init (&proxy->lock); + return proxy; } @@ -96,6 +102,8 @@ dbus_gproxy_new_for_service (DBusConnection *connection, /** * Increment reference count on proxy object. * + * @todo use GAtomic to avoid locking + * * @param proxy the proxy */ void @@ -103,11 +111,17 @@ dbus_gproxy_ref (DBusGProxy *proxy) { g_return_if_fail (proxy != NULL); + LOCK_PROXY (proxy); + proxy->refcount += 1; + + UNLOCK_PROXY (proxy); } /** * Decrement reference count on proxy object. + * + * @todo use GAtomic to avoid locking * * @param proxy the proxy */ @@ -116,23 +130,35 @@ dbus_gproxy_unref (DBusGProxy *proxy) { g_return_if_fail (proxy != NULL); - proxy->refcount -= 1; + LOCK_PROXY (proxy); + + proxy->refcount -= 1; + if (proxy->refcount == 0) { + UNLOCK_PROXY (proxy); + dbus_connection_unref (proxy->connection); g_free (proxy->interface); g_free (proxy->service); + g_static_mutex_free (&proxy->lock); g_free (proxy); } + else + { + UNLOCK_PROXY (proxy); + } } /** * Invokes a method on a remote interface. This function does not - * block; instead it returns an opaque #DBusGPendingCall object that + * block; instead it returns an opaque #DBusPendingCall object that * tracks the pending call. The method call will not be sent over the * wire until the application returns to the main loop, or blocks in * dbus_connection_flush() to write out pending data. The call will * be completed after a timeout, or when a reply is received. + * To collect the results of the call (which may be an error, + * or a reply), use dbus_gproxy_end_call(). * * @param proxy a proxy for a remote interface * @param method the name of the method to invoke @@ -141,14 +167,96 @@ dbus_gproxy_unref (DBusGProxy *proxy) * @returns opaque pending call object * */ -DBusGPendingCall* +DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, const char *method, int first_arg_type, ...) { + g_return_val_if_fail (proxy != NULL, NULL); + LOCK_PROXY (proxy); + + UNLOCK_PROXY (proxy); +} + +/** + * Collects the results of a method call. The method call was normally + * initiated with dbus_gproxy_end_call(). This function will block if + * the results haven't yet been received; use + * dbus_pending_call_set_notify() to be notified asynchronously that a + * pending call has been completed. + * + * If the call results in an error, the error is set as normal for + * GError and the function returns #FALSE. + * + * Otherwise, the "out" parameters and return value of the + * method are stored in the provided varargs list. + * The list should be terminated with DBUS_TYPE_INVALID. + * + * @param proxy a proxy for a remote interface + * @param pending the pending call from dbus_gproxy_begin_call() + * @param error return location for an error + * @param first_arg_type type of first "out" argument + * @returns #FALSE if an error is set + */ +gboolean +dbus_gproxy_end_call (DBusGProxy *proxy, + DBusPendingCall *pending, + GError **error, + int first_arg_type, + ...) +{ + g_return_val_if_fail (proxy != NULL, FALSE); + LOCK_PROXY (proxy); + + UNLOCK_PROXY (proxy); +} + +/** + * Sends a message to the interface we're proxying for. Does not + * block or wait for a reply. The message is only actually written out + * when you return to the main loop or block in + * dbus_connection_flush(). + * + * The message is modified to be addressed to the target interface. + * That is, a destination service field or whatever is needed + * will be added to the message. + * + * This function adds a reference to the message, so the caller + * still owns its original reference. + * + * @todo fix for sending to interfaces and object IDs + * + * @param proxy a proxy for a remote interface + * @param message the message to address and send + * @param client_serial return location for message's serial, or #NULL + */ +void +dbus_gproxy_send (DBusGProxy *proxy, + DBusMessage *message, + dbus_uint32_t *client_serial) +{ + g_return_if_fail (proxy != NULL); + LOCK_PROXY (proxy); - + if (proxy->service) + { + if (!dbus_message_set_destination (message, proxy->service)) + g_error ("Out of memory\n"); + } + if (proxy->interface) + { + /* FIXME */ + } + if (!dbus_object_id_is_null (&proxy->object_id)) + { + /* FIXME */ + } + + if (!dbus_connection_send (proxy->connection, message, client_serial)) + g_error ("Out of memory\n"); + + UNLOCK_PROXY (proxy); } /** @} End of DBusGLib public */ diff --git a/glib/dbus-gproxy.h b/glib/dbus-gproxy.h index 47b70f36..f40ce8a0 100644 --- a/glib/dbus-gproxy.h +++ b/glib/dbus-gproxy.h @@ -34,7 +34,6 @@ G_BEGIN_DECLS typedef struct DBusGProxy DBusGProxy; -typedef struct DBusPendingCall DBusPendingCall; DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, const char *service_name, @@ -60,18 +59,18 @@ DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, const char *method, int first_arg_type, ...); -void dbus_gproxy_oneway_call (DBusGProxy *proxy, - const char *method, +gboolean dbus_gproxy_end_call (DBusGProxy *proxy, + DBusPendingCall *pending, + GError **error, int first_arg_type, ...); -gboolean dbus_pending_call_is_complete (DBusPendingCall *call); -void dbus_pending_call_cancel_and_free (DBusPendingCall *call); -gboolean dbus_pending_call_block_and_free (DBusPendingCall *call, - GError **error, +void dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, int first_arg_type, ...); - - +void dbus_gproxy_send (DBusGProxy *proxy, + DBusMessage *message, + dbus_uint32_t *client_serial); G_END_DECLS -- cgit v1.2.1 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 --- ChangeLog | 30 ++++ bus/bus.c | 33 ++-- bus/config-parser.c | 188 ++++++++++++++------- bus/connection.c | 26 ++- bus/dispatch.c | 47 +++--- bus/policy.c | 76 +++++++-- bus/policy.h | 12 +- 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 +- 18 files changed, 1224 insertions(+), 414 deletions(-) diff --git a/ChangeLog b/ChangeLog index b2f71f14..e22c0de0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +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 + 2003-08-16 Havoc Pennington * dbus/dbus-object-registry.c (add_and_remove_objects): remove diff --git a/bus/bus.c b/bus/bus.c index a5530974..58a10967 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -870,20 +870,21 @@ bus_context_check_security_policy (BusContext *context, * the hello message to the bus driver */ if (recipient == NULL && - dbus_message_has_name (message, DBUS_MESSAGE_HELLO)) + dbus_message_has_interface (message, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) && + dbus_message_has_member (message, "Hello")) { _dbus_verbose ("security check allowing %s message\n", - DBUS_MESSAGE_HELLO); + "Hello"); return TRUE; } else { _dbus_verbose ("security check disallowing non-%s message\n", - DBUS_MESSAGE_HELLO); + "Hello"); dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Client tried to send a message other than %s without being registered", - DBUS_MESSAGE_HELLO); + "Hello"); return FALSE; } @@ -934,9 +935,14 @@ bus_context_check_security_policy (BusContext *context, "A security policy in place prevents this sender " "from sending this message to this recipient, " "see message bus configuration file (rejected message " - "had name \"%s\" destination \"%s\")", - dbus_message_get_name (message), - dest ? dest : DBUS_SERVICE_DBUS); + "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to sender policy\n"); return FALSE; } @@ -951,9 +957,14 @@ bus_context_check_security_policy (BusContext *context, "A security policy in place prevents this recipient " "from receiving this message from this sender, " "see message bus configuration file (rejected message " - "had name \"%s\" destination \"%s\")", - dbus_message_get_name (message), - dest ? dest : DBUS_SERVICE_DBUS); + "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to recipient policy\n"); return FALSE; } @@ -966,7 +977,7 @@ bus_context_check_security_policy (BusContext *context, const char *dest = dbus_message_get_destination (message); dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "The destination service \"%s\" has a full message queue", - dest ? dest : DBUS_SERVICE_DBUS); + dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); _dbus_verbose ("security policy disallowing message due to full message queue\n"); return FALSE; } diff --git a/bus/config-parser.c b/bus/config-parser.c index c42278e1..471c67d8 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -816,11 +816,15 @@ append_rule_from_element (BusConfigParser *parser, dbus_bool_t allow, DBusError *error) { - const char *send; - const char *receive; + const char *send_interface; + const char *send_member; + const char *send_error; + const char *send_service; + const char *receive_interface; + const char *receive_member; + const char *receive_error; + const char *receive_service; const char *own; - const char *send_to; - const char *receive_from; const char *user; const char *group; BusPolicyRule *rule; @@ -829,57 +833,112 @@ append_rule_from_element (BusConfigParser *parser, attribute_names, attribute_values, error, - "send", &send, - "receive", &receive, + "send_interface", &send_interface, + "send_member", &send_member, + "send_error", &send_error, + "send_service", &send_service, + "receive_interface", &receive_interface, + "receive_member", &receive_member, + "receive_error", &receive_error, + "receive_service", &receive_service, "own", &own, - "send_to", &send_to, - "receive_from", &receive_from, "user", &user, "group", &group, NULL)) return FALSE; - if (!(send || receive || own || send_to || receive_from || - user || group)) + if (!(send_interface || send_member || send_error || send_service || + receive_interface || receive_member || receive_error || receive_service || + own || user || group)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Element <%s> must have one or more attributes", element_name); return FALSE; } - - if (((send && own) || - (send && receive) || - (send && receive_from) || - (send && user) || - (send && group)) || - - ((receive && own) || - (receive && send_to) || - (receive && user) || - (receive && group)) || - - ((own && send_to) || - (own && receive_from) || - (own && user) || - (own && group)) || - ((send_to && receive_from) || - (send_to && user) || - (send_to && group)) || + if ((send_member && send_interface == NULL) || + (receive_member && receive_interface == NULL)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "On element <%s>, if you specify a member you must specify an interface", + element_name); + return FALSE; + } + + /* Allowed combinations of elements are: + * + * base, must be all send or all receive: + * interface + * interface + member + * error + * + * base send_ can combine with send_service, + * base receive_ with receive_service + * + * user, group, own must occur alone + */ - ((receive_from && user) || - (receive_from && group)) || + if (((send_interface && send_error) || + (send_interface && receive_interface) || + (send_interface && receive_member) || + (send_interface && receive_error) || + (send_interface && receive_service) || + (send_interface && own) || + (send_interface && user) || + (send_interface && group)) || + + ((send_member && send_error) || + (send_member && receive_interface) || + (send_member && receive_member) || + (send_member && receive_error) || + (send_member && receive_service) || + (send_member && own) || + (send_member && user) || + (send_member && group)) || + + ((send_error && receive_interface) || + (send_error && receive_member) || + (send_error && receive_error) || + (send_error && receive_service) || + (send_error && own) || + (send_error && user) || + (send_error && group)) || + + ((send_service && receive_interface) || + (send_service && receive_member) || + (send_service && receive_error) || + (send_service && receive_service) || + (send_service && own) || + (send_service && user) || + (send_service && group)) || + + ((receive_interface && receive_error) || + (receive_interface && own) || + (receive_interface && user) || + (receive_interface && group)) || + + ((receive_member && receive_error) || + (receive_member && own) || + (receive_member && user) || + (receive_member && group)) || + + ((receive_error && own) || + (receive_error && user) || + (receive_error && group)) || + + ((own && user) || + (own && group)) || - (user && group)) + ((user && group))) { dbus_set_error (error, DBUS_ERROR_FAILED, "Invalid combination of attributes on element <%s>, " - "only send/send_to or receive/receive_from may be paired", + "only send_foo/send_service or receive_foo/receive_service may be paired", element_name); return FALSE; } - + rule = NULL; /* In BusPolicyRule, NULL represents wildcard. @@ -887,41 +946,60 @@ append_rule_from_element (BusConfigParser *parser, */ #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') - if (send || send_to) + if (send_interface || send_member || send_error || send_service) { rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); if (rule == NULL) goto nomem; - - if (IS_WILDCARD (send)) - send = NULL; - if (IS_WILDCARD (send_to)) - send_to = NULL; - rule->d.send.message_name = _dbus_strdup (send); - rule->d.send.destination = _dbus_strdup (send_to); - if (send && rule->d.send.message_name == NULL) + if (IS_WILDCARD (send_interface)) + send_interface = NULL; + if (IS_WILDCARD (send_member)) + send_member = NULL; + if (IS_WILDCARD (send_error)) + send_error = NULL; + if (IS_WILDCARD (send_service)) + send_service = NULL; + + rule->d.send.interface = _dbus_strdup (send_interface); + rule->d.send.member = _dbus_strdup (send_member); + rule->d.send.error = _dbus_strdup (send_error); + rule->d.send.destination = _dbus_strdup (send_service); + if (send_interface && rule->d.send.interface == NULL) + goto nomem; + if (send_member && rule->d.send.member == NULL) goto nomem; - if (send_to && rule->d.send.destination == NULL) + if (send_error && rule->d.send.error == NULL) + goto nomem; + if (send_service && rule->d.send.destination == NULL) goto nomem; } - else if (receive || receive_from) + else if (receive_interface || receive_member || receive_error || receive_service) { rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); if (rule == NULL) goto nomem; - - if (IS_WILDCARD (receive)) - receive = NULL; - - if (IS_WILDCARD (receive_from)) - receive_from = NULL; - rule->d.receive.message_name = _dbus_strdup (receive); - rule->d.receive.origin = _dbus_strdup (receive_from); - if (receive && rule->d.receive.message_name == NULL) + if (IS_WILDCARD (receive_interface)) + receive_interface = NULL; + if (IS_WILDCARD (receive_member)) + receive_member = NULL; + if (IS_WILDCARD (receive_error)) + receive_error = NULL; + if (IS_WILDCARD (receive_service)) + receive_service = NULL; + + rule->d.receive.interface = _dbus_strdup (receive_interface); + rule->d.receive.member = _dbus_strdup (receive_member); + rule->d.receive.error = _dbus_strdup (receive_error); + rule->d.receive.origin = _dbus_strdup (receive_service); + if (receive_interface && rule->d.receive.interface == NULL) + goto nomem; + if (receive_member && rule->d.receive.member == NULL) + goto nomem; + if (receive_error && rule->d.receive.error == NULL) goto nomem; - if (receive_from && rule->d.receive.origin == NULL) + if (receive_service && rule->d.receive.origin == NULL) goto nomem; } else if (own) diff --git a/bus/connection.c b/bus/connection.c index e588039e..4df00bfd 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -972,10 +972,10 @@ bus_connection_preallocate_oom_error (DBusConnection *connection) } /* d->name may be NULL, but that is OK */ - if (!dbus_message_set_name (message, DBUS_ERROR_NO_MEMORY) || + if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) || !dbus_message_set_destination (message, d->name) || !dbus_message_set_sender (message, - DBUS_SERVICE_DBUS)) + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { dbus_connection_free_preallocated_send (connection, preallocated); dbus_message_unref (message); @@ -1312,10 +1312,15 @@ bus_transaction_send_from_driver (BusTransaction *transaction, * to check security policy since it was not done in * dispatch.c */ - _dbus_verbose ("Sending %s from driver\n", - dbus_message_get_name (message)); - - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + _dbus_verbose ("Sending %s %s %s from driver\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(no interface)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(no member)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(no error name)"); + + if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) return FALSE; /* If security policy doesn't allow the message, we silently @@ -1337,11 +1342,16 @@ bus_transaction_send (BusTransaction *transaction, BusConnectionData *d; DBusList *link; - _dbus_verbose (" trying to add %s %s to transaction%s\n", + _dbus_verbose (" trying to add %s interface=%s member=%s error=%s to transaction%s\n", dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" : dbus_message_get_reply_serial (message) != 0 ? "reply" : "message", - dbus_message_get_name (message), + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", dbus_connection_get_is_connected (connection) ? "" : " (disconnected)"); diff --git a/bus/dispatch.c b/bus/dispatch.c index e8f0c9ba..934619f1 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -104,7 +104,7 @@ static DBusHandlerResult bus_dispatch (DBusConnection *connection, DBusMessage *message) { - const char *sender, *service_name, *message_name; + const char *sender, *service_name; DBusError error; BusTransaction *transaction; BusContext *context; @@ -126,14 +126,24 @@ bus_dispatch (DBusConnection *connection, /* Ref connection in case we disconnect it at some point in here */ dbus_connection_ref (connection); - + service_name = dbus_message_get_destination (message); - message_name = dbus_message_get_name (message); - - _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */ - _dbus_verbose ("DISPATCH: %s to %s\n", - message_name, service_name ? service_name : "peer"); +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + const char *interface_name, *member_name, *error_name; + + interface_name = dbus_message_get_interface (message); + member_name = dbus_message_get_member (message); + error_name = dbus_message_get_error_name (message); + + _dbus_verbose ("DISPATCH: %s %s %s to %s\n", + interface_name ? interface_name : "(no interface)", + member_name ? member_name : "(no member)", + error_name ? error_name : "(no error name)", + service_name ? service_name : "peer"); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ /* If service_name is NULL, this is a message to the bus daemon, not * intended to actually go "on the bus"; e.g. a peer-to-peer @@ -142,7 +152,8 @@ bus_dispatch (DBusConnection *connection, */ if (service_name == NULL) { - if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0) + if (dbus_message_has_interface (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL) && + dbus_message_has_member (message, "Disconnect")) bus_connection_disconnected (connection); /* DBusConnection also handles some of these automatically, we leave @@ -182,7 +193,7 @@ bus_dispatch (DBusConnection *connection, service_name = dbus_message_get_destination (message); } - if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */ + if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */ { if (!bus_context_check_security_policy (context, connection, NULL, message, &error)) @@ -191,7 +202,7 @@ bus_dispatch (DBusConnection *connection, goto out; } - _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS); + _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (!bus_driver_handle_message (connection, transaction, message, &error)) goto out; } @@ -679,7 +690,7 @@ check_hello_message (BusContext *context, message = NULL; message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -721,7 +732,7 @@ check_hello_message (BusContext *context, _dbus_verbose ("Received %s on %p\n", dbus_message_get_name (message), connection); - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -911,7 +922,7 @@ check_nonexistent_service_activation (BusContext *context, dbus_error_init (&error); message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -959,7 +970,7 @@ check_nonexistent_service_activation (BusContext *context, if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1465,7 +1476,7 @@ check_existent_service_activation (BusContext *context, dbus_error_init (&error); message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -1519,7 +1530,7 @@ check_existent_service_activation (BusContext *context, if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? @@ -1673,7 +1684,7 @@ check_segfault_service_activation (BusContext *context, dbus_error_init (&error); message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) return TRUE; @@ -1722,7 +1733,7 @@ check_segfault_service_activation (BusContext *context, if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { _dbus_warn ("Message has wrong sender %s\n", dbus_message_get_sender (message) ? diff --git a/bus/policy.c b/bus/policy.c index 2f8e2ca3..3b3ceb4e 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -80,11 +80,15 @@ bus_policy_rule_unref (BusPolicyRule *rule) switch (rule->type) { case BUS_POLICY_RULE_SEND: - dbus_free (rule->d.send.message_name); + dbus_free (rule->d.send.interface); + dbus_free (rule->d.send.member); + dbus_free (rule->d.send.error); dbus_free (rule->d.send.destination); break; case BUS_POLICY_RULE_RECEIVE: - dbus_free (rule->d.receive.message_name); + dbus_free (rule->d.receive.interface); + dbus_free (rule->d.receive.member); + dbus_free (rule->d.receive.error); dbus_free (rule->d.receive.origin); break; case BUS_POLICY_RULE_OWN: @@ -680,8 +684,8 @@ bus_client_policy_optimize (BusClientPolicy *policy) /* The idea here is that if we have: * - * - * + * + * * * (for example) the deny will always override the allow. So we * delete the allow. Ditto for deny followed by allow, etc. This is @@ -713,12 +717,16 @@ bus_client_policy_optimize (BusClientPolicy *policy) { case BUS_POLICY_RULE_SEND: remove_preceding = - rule->d.send.message_name == NULL && + rule->d.send.interface == NULL && + rule->d.send.member == NULL && + rule->d.send.error == NULL && rule->d.send.destination == NULL; break; case BUS_POLICY_RULE_RECEIVE: remove_preceding = - rule->d.receive.message_name == NULL && + rule->d.receive.interface == NULL && + rule->d.receive.member == NULL && + rule->d.receive.error == NULL && rule->d.receive.origin == NULL; break; case BUS_POLICY_RULE_OWN: @@ -791,16 +799,34 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, continue; } - if (rule->d.send.message_name != NULL) + if (rule->d.send.interface != NULL) { - if (!dbus_message_has_name (message, - rule->d.send.message_name)) + if (!dbus_message_has_interface (message, + rule->d.send.interface)) { - _dbus_verbose (" (policy) skipping rule for different message name\n"); + _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; } } - + else if (rule->d.send.member != NULL) + { + if (!dbus_message_has_member (message, + rule->d.send.member)) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + else if (rule->d.send.error != NULL) + { + if (!dbus_message_has_error_name (message, + rule->d.send.error)) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + if (rule->d.send.destination != NULL) { /* receiver can be NULL for messages that are sent to the @@ -886,16 +912,34 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, continue; } - if (rule->d.receive.message_name != NULL) + if (rule->d.receive.interface != NULL) { - if (!dbus_message_has_name (message, - rule->d.receive.message_name)) + if (!dbus_message_has_interface (message, + rule->d.receive.interface)) { - _dbus_verbose (" (policy) skipping rule for different message name\n"); + _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; } } - + else if (rule->d.receive.member != NULL) + { + if (!dbus_message_has_member (message, + rule->d.receive.member)) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + else if (rule->d.receive.error != NULL) + { + if (!dbus_message_has_error_name (message, + rule->d.receive.error)) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + if (rule->d.receive.origin != NULL) { /* sender can be NULL for messages that originate from the diff --git a/bus/policy.h b/bus/policy.h index 940085ee..2aa69aaf 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -54,15 +54,19 @@ struct BusPolicyRule { struct { - /* either can be NULL meaning "any" */ - char *message_name; + /* any of these can be NULL meaning "any" */ + char *interface; + char *member; + char *error; char *destination; } send; struct { - /* either can be NULL meaning "any" */ - char *message_name; + /* any of these can be NULL meaning "any" */ + char *interface; + char *member; + char *error; char *origin; } receive; 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 v1.2.1 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" --- ChangeLog | 24 +++ bus/bus.c | 5 +- bus/connection.c | 2 +- bus/dispatch.c | 186 ++++++++++++--------- bus/driver.c | 61 ++++--- bus/policy.c | 30 ++-- bus/test.c | 5 +- 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 + doc/TODO | 3 - glib/test-dbus-glib.c | 7 +- glib/test-profile.c | 28 +++- glib/test-thread-client.c | 3 +- glib/test-thread-server.c | 6 +- test/data/incomplete-messages/missing-body.message | 7 +- test/data/invalid-messages/array-of-nil.message | 9 +- .../array-with-mixed-types.message | 9 +- .../invalid-messages/bad-boolean-array.message | 9 +- test/data/invalid-messages/bad-boolean.message | 9 +- test/data/invalid-messages/bad-endian.message | 14 +- test/data/invalid-messages/local-namespace.message | 11 +- test/data/invalid-messages/no-dot-in-name.message | 13 +- .../not-nul-header-padding.message | 10 +- test/data/invalid-messages/overlong-name.message | 9 +- .../too-little-header-padding.message | 10 +- .../too-much-header-padding-by-far.message | 10 +- .../too-much-header-padding.message | 10 +- test/data/invalid-messages/too-short-dict.message | 13 +- .../array-of-array-of-uint32.message | 7 +- test/data/valid-messages/dict-simple.message | 7 +- test/data/valid-messages/dict.message | 7 +- test/data/valid-messages/emptiness.message | 7 +- test/data/valid-messages/lots-of-arguments.message | 7 +- test/data/valid-messages/no-padding.message | 7 +- test/data/valid-messages/opposite-endian.message | 11 +- test/data/valid-messages/recursive-types.message | 7 +- test/data/valid-messages/simplest-manual.message | 7 +- test/data/valid-messages/simplest.message | 9 +- .../standard-acquire-service.message | 9 +- test/data/valid-messages/standard-hello.message | 9 +- .../valid-messages/standard-list-services.message | 9 +- .../valid-messages/standard-service-exists.message | 9 +- .../valid-messages/unknown-header-field.message | 7 +- test/test-service.c | 12 +- tools/dbus-monitor.c | 4 +- tools/dbus-print-message.c | 37 +++- tools/dbus-send.1 | 8 +- tools/dbus-send.c | 30 +++- 53 files changed, 672 insertions(+), 281 deletions(-) diff --git a/ChangeLog b/ChangeLog index e22c0de0..4a2d6a88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +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" + 2003-08-17 Havoc Pennington This doesn't compile yet, but syncing up so I can hack on it from diff --git a/bus/bus.c b/bus/bus.c index 58a10967..1b461fe3 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -870,8 +870,9 @@ bus_context_check_security_policy (BusContext *context, * the hello message to the bus driver */ if (recipient == NULL && - dbus_message_has_interface (message, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) && - dbus_message_has_member (message, "Hello")) + dbus_message_is_method_call (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello")) { _dbus_verbose ("security check allowing %s message\n", "Hello"); diff --git a/bus/connection.c b/bus/connection.c index 4df00bfd..f6ce4a29 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -1560,7 +1560,7 @@ bus_transaction_send_error_reply (BusTransaction *transaction, _dbus_assert (error != NULL); _DBUS_ASSERT_ERROR_IS_SET (error); - + _dbus_verbose ("Sending error reply %s \"%s\"\n", error->name, error->message); diff --git a/bus/dispatch.c b/bus/dispatch.c index 934619f1..8eda2500 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -152,8 +152,9 @@ bus_dispatch (DBusConnection *connection, */ if (service_name == NULL) { - if (dbus_message_has_interface (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL) && - dbus_message_has_member (message, "Disconnect")) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) bus_connection_disconnected (connection); /* DBusConnection also handles some of these automatically, we leave @@ -215,7 +216,7 @@ bus_dispatch (DBusConnection *connection, * on services that all service owners will get messages to it, not just * the primary owner. */ - else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */ + else if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST) == 0) /* spam! */ { if (!bus_dispatch_broadcast_message (transaction, connection, message, &error)) goto out; @@ -416,6 +417,22 @@ pop_message_waiting_for_memory (DBusConnection *connection) return dbus_connection_pop_message (connection); } +static void +warn_unexpected (DBusConnection *connection, + DBusMessage *message, + const char *expected) +{ + _dbus_warn ("Received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + connection, + expected); +} + typedef struct { const char *expected_service_name; @@ -439,14 +456,15 @@ check_service_deleted_foreach (DBusConnection *connection, if (message == NULL) { _dbus_warn ("Did not receive a message on %p, expecting %s\n", - connection, DBUS_MESSAGE_SERVICE_DELETED); + connection, "ServiceDeleted"); goto out; } - else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED)) + else if (!dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceDeleted")) { - _dbus_warn ("Received message %s on %p, expecting %s\n", - dbus_message_get_name (message), - connection, DBUS_MESSAGE_SERVICE_DELETED); + warn_unexpected (connection, message, "ServiceDeleted"); + goto out; } else @@ -569,8 +587,8 @@ check_no_messages_foreach (DBusConnection *connection, message = pop_message_waiting_for_memory (connection); if (message != NULL) { - _dbus_warn ("Received message %s on %p, expecting no messages\n", - dbus_message_get_name (message), connection); + warn_unexpected (connection, message, "no messages"); + d->failed = TRUE; } @@ -606,14 +624,14 @@ check_service_created_foreach (DBusConnection *connection, if (message == NULL) { _dbus_warn ("Did not receive a message on %p, expecting %s\n", - connection, DBUS_MESSAGE_SERVICE_CREATED); + connection, "ServiceCreated"); goto out; } - else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) + else if (!dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated")) { - _dbus_warn ("Received message %s on %p, expecting %s\n", - dbus_message_get_name (message), - connection, DBUS_MESSAGE_SERVICE_CREATED); + warn_unexpected (connection, message, "ServiceCreated"); goto out; } else @@ -689,7 +707,8 @@ check_hello_message (BusContext *context, acquired = NULL; message = NULL; - message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, + message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) @@ -725,12 +744,12 @@ check_hello_message (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive a reply to %s %d on %p\n", - DBUS_MESSAGE_HELLO, serial, connection); + "Hello", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p\n", - dbus_message_get_name (message), connection); + _dbus_verbose ("Received message %p on %p\n", + message, connection); if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { @@ -742,15 +761,15 @@ check_hello_message (BusContext *context, if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { - if (dbus_message_has_name (message, + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } else { - _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "not this error"); + goto out; } } @@ -758,15 +777,14 @@ check_hello_message (BusContext *context, { CheckServiceCreatedData scd; - if (dbus_message_has_name (message, - DBUS_MESSAGE_HELLO)) + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) { ; /* good, expected */ } else { - _dbus_warn ("Did not expect reply %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "method return for Hello"); + goto out; } @@ -810,7 +828,7 @@ check_hello_message (BusContext *context, if (message == NULL) { _dbus_warn ("Expecting %s, got nothing\n", - DBUS_MESSAGE_SERVICE_ACQUIRED); + "ServiceAcquired"); goto out; } @@ -921,7 +939,8 @@ check_nonexistent_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) @@ -961,12 +980,12 @@ check_nonexistent_service_activation (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive a reply to %s %d on %p\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection); + "ActivateService", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p\n", - dbus_message_get_name (message), connection); + _dbus_verbose ("Received message %p on %p\n", + message, connection); if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { @@ -978,20 +997,19 @@ check_nonexistent_service_activation (BusContext *context, goto out; } - if (dbus_message_has_name (message, + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_has_name (message, + else if (dbus_message_is_error (message, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND)) { ; /* good, this is expected also */ } else { - _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "not this error"); goto out; } } @@ -1030,7 +1048,9 @@ check_base_service_activated (BusContext *context, message = initial_message; dbus_message_ref (message); - if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated")) { char *service_name; CheckServiceCreatedData scd; @@ -1049,7 +1069,7 @@ check_base_service_activated (BusContext *context, else { _dbus_warn ("Message %s doesn't have a service name: %s\n", - dbus_message_get_name (message), + "ServiceCreated", error.message); dbus_error_free (&error); goto out; @@ -1077,8 +1097,8 @@ check_base_service_activated (BusContext *context, } else { - _dbus_warn ("Expected to get base service ServiceCreated, instead got %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "ServiceCreated for base service"); + goto out; } @@ -1119,7 +1139,9 @@ check_service_activated (BusContext *context, message = initial_message; dbus_message_ref (message); - if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED)) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated")) { char *service_name; CheckServiceCreatedData scd; @@ -1138,7 +1160,7 @@ check_service_activated (BusContext *context, else { _dbus_warn ("Message %s doesn't have a service name: %s\n", - dbus_message_get_name (message), + "ServiceCreated", error.message); dbus_error_free (&error); goto out; @@ -1169,22 +1191,21 @@ check_service_activated (BusContext *context, if (message == NULL) { _dbus_warn ("Expected a reply to %s, got nothing\n", - DBUS_MESSAGE_ACTIVATE_SERVICE); + "ActivateService"); goto out; } } else { - _dbus_warn ("Expected to get service %s ServiceCreated, instead got %s\n", - activated_name, dbus_message_get_name (message)); + warn_unexpected (connection, message, "ServiceCreated for the activated name"); + goto out; } - if (!dbus_message_has_name (message, DBUS_MESSAGE_ACTIVATE_SERVICE)) + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) { - _dbus_warn ("Expected reply to %s, got message %s instead\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, - dbus_message_get_name (message)); + warn_unexpected (connection, message, "reply to ActivateService"); + goto out; } @@ -1196,7 +1217,7 @@ check_service_activated (BusContext *context, if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { _dbus_warn ("Did not have activation result first argument to %s: %s\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, error.message); + "ActivateService", error.message); dbus_error_free (&error); goto out; } @@ -1302,7 +1323,8 @@ check_send_exit_to_service (BusContext *context, retval = FALSE; /* Kill off the test service by sending it a quit message */ - message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteExit", + message = dbus_message_new_method_call ("org.freedesktop.TestSuite", + "Exit", service_name); if (message == NULL) @@ -1359,21 +1381,16 @@ check_send_exit_to_service (BusContext *context, message = pop_message_waiting_for_memory (connection); _dbus_assert (message != NULL); - if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) - { - _dbus_warn ("expecting an error reply to asking test service to exit, got %s\n", - dbus_message_get_name (message)); - goto out; - } - else if (!dbus_message_has_name (message, DBUS_ERROR_NO_MEMORY)) + if (!dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) { - _dbus_warn ("not expecting error %s when asking test service to exit\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, + "a no memory error from asking test service to exit"); goto out; } _dbus_verbose ("Got error %s when asking test service to exit\n", - dbus_message_get_name (message)); + dbus_message_get_error_name (message)); /* Do this again; we still need the service to exit... */ if (!check_send_exit_to_service (context, connection, @@ -1419,8 +1436,8 @@ check_got_error (BusContext *context, if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) { - _dbus_warn ("Expected an error, got %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "an error"); + goto out; } @@ -1430,7 +1447,7 @@ check_got_error (BusContext *context, error_name = first_error_name; while (error_name != NULL) { - if (dbus_message_has_name (message, error_name)) + if (dbus_message_is_error (message, error_name)) { error_found = TRUE; break; @@ -1443,7 +1460,7 @@ check_got_error (BusContext *context, { _dbus_warn ("Expected error %s or other, got %s instead\n", first_error_name, - dbus_message_get_name (message)); + dbus_message_get_error_name (message)); goto out; } @@ -1475,7 +1492,8 @@ check_existent_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) @@ -1520,13 +1538,12 @@ check_existent_service_activation (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive any messages after %s %d on %p\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection); + "ActivateService", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p after sending %s\n", - dbus_message_get_name (message), connection, - DBUS_MESSAGE_ACTIVATE_SERVICE); + _dbus_verbose ("Received message %p on %p after sending %s\n", + message, connection, "ActivateService"); if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { @@ -1538,12 +1555,12 @@ check_existent_service_activation (BusContext *context, goto out; } - if (dbus_message_has_name (message, + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_has_name (message, + else if (dbus_message_is_error (message, DBUS_ERROR_SPAWN_CHILD_EXITED)) { ; /* good, this is expected also */ @@ -1551,7 +1568,7 @@ check_existent_service_activation (BusContext *context, else { _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + dbus_message_get_error_name (message)); goto out; } } @@ -1577,7 +1594,9 @@ check_existent_service_activation (BusContext *context, goto out; } - got_service_deleted = dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED); + got_service_deleted = dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceDeleted"); got_error = dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR; dbus_connection_return_message (connection, message); @@ -1683,7 +1702,8 @@ check_segfault_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); if (message == NULL) @@ -1724,12 +1744,12 @@ check_segfault_service_activation (BusContext *context, if (message == NULL) { _dbus_warn ("Did not receive a reply to %s %d on %p\n", - DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection); + "ActivateService", serial, connection); goto out; } - _dbus_verbose ("Received %s on %p\n", - dbus_message_get_name (message), connection); + _dbus_verbose ("Received message %p on %p\n", + message, connection); if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { @@ -1741,20 +1761,20 @@ check_segfault_service_activation (BusContext *context, goto out; } - if (dbus_message_has_name (message, - DBUS_ERROR_NO_MEMORY)) + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) { ; /* good, this is a valid response */ } - else if (dbus_message_has_name (message, - DBUS_ERROR_SPAWN_CHILD_SIGNALED)) + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_SIGNALED)) { ; /* good, this is expected also */ } else { - _dbus_warn ("Did not expect error %s\n", - dbus_message_get_name (message)); + warn_unexpected (connection, message, "not this error"); + goto out; } } diff --git a/bus/driver.c b/bus/driver.c index 22e36e0a..7fd9cd87 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -49,7 +49,8 @@ bus_driver_send_service_deleted (const char *service_name, _dbus_verbose ("sending service deleted: %s\n", service_name); - message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_DELETED); + message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceDeleted"); if (message == NULL) { @@ -57,7 +58,7 @@ bus_driver_send_service_deleted (const char *service_name, return FALSE; } - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || + if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) || !dbus_message_append_args (message, DBUS_TYPE_STRING, service_name, DBUS_TYPE_INVALID)) @@ -83,7 +84,8 @@ bus_driver_send_service_created (const char *service_name, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_CREATED); + message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceCreated"); if (message == NULL) { @@ -91,7 +93,7 @@ bus_driver_send_service_created (const char *service_name, return FALSE; } - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { dbus_message_unref (message); BUS_SET_OOM (error); @@ -123,7 +125,8 @@ bus_driver_send_service_lost (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_LOST); + message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceLost"); if (message == NULL) { @@ -164,7 +167,8 @@ bus_driver_send_service_acquired (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new_signal (DBUS_MESSAGE_SERVICE_ACQUIRED); + message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceAcquired"); if (message == NULL) { @@ -604,11 +608,11 @@ struct DBusMessage *message, DBusError *error); } message_handlers[] = { - { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service }, - { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service }, - { DBUS_MESSAGE_HELLO, bus_driver_handle_hello }, - { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists }, - { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services } + { "AcquireService", bus_driver_handle_acquire_service }, + { "ActivateService", bus_driver_handle_activate_service }, + { "Hello", bus_driver_handle_hello }, + { "ServiceExists", bus_driver_handle_service_exists }, + { "ListServices", bus_driver_handle_list_services } }; dbus_bool_t @@ -621,15 +625,32 @@ bus_driver_handle_message (DBusConnection *connection, int i; _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + { + _dbus_verbose ("Driver got a non-method-call message, ignoring\n"); + return TRUE; /* we just ignore this */ + } + + _dbus_assert (dbus_message_get_interface (message) != NULL); + _dbus_assert (dbus_message_get_member (message) != NULL); + + name = dbus_message_get_member (message); + sender = dbus_message_get_sender (message); - _dbus_verbose ("Driver got a message: %s\n", - dbus_message_get_name (message)); + if (strcmp (dbus_message_get_interface (message), + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) != 0) + { + _dbus_verbose ("Driver got message to unknown interface \"%s\"\n", + dbus_message_get_interface (message)); + goto unknown; + } + + _dbus_verbose ("Driver got a method call: %s\n", + dbus_message_get_member (message)); - name = dbus_message_get_name (message); - sender = dbus_message_get_sender (message); - /* security checks should have kept this from getting here */ - _dbus_assert (sender != NULL || strcmp (name, DBUS_MESSAGE_HELLO) == 0); + _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0); if (dbus_message_get_reply_serial (message) == 0) { @@ -660,11 +681,13 @@ bus_driver_handle_message (DBusConnection *connection, ++i; } - _dbus_verbose ("No driver handler for %s\n", name); + unknown: + _dbus_verbose ("No driver handler for message \"%s\"\n", + name); dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD, "%s does not understand message %s", - DBUS_SERVICE_DBUS, name); + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, name); return FALSE; } diff --git a/bus/policy.c b/bus/policy.c index 3b3ceb4e..04ea4230 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -801,8 +801,9 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, if (rule->d.send.interface != NULL) { - if (!dbus_message_has_interface (message, - rule->d.send.interface)) + if (dbus_message_get_interface (message) == NULL || + strcmp (dbus_message_get_interface (message), + rule->d.send.interface) != 0) { _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; @@ -810,8 +811,9 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, } else if (rule->d.send.member != NULL) { - if (!dbus_message_has_member (message, - rule->d.send.member)) + if (dbus_message_get_member (message) == NULL || + strcmp (dbus_message_get_member (message), + rule->d.send.member) != 0) { _dbus_verbose (" (policy) skipping rule for different member\n"); continue; @@ -819,8 +821,9 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, } else if (rule->d.send.error != NULL) { - if (!dbus_message_has_error_name (message, - rule->d.send.error)) + if (dbus_message_get_error_name (message) == NULL || + strcmp (dbus_message_get_error_name (message), + rule->d.send.error) != 0) { _dbus_verbose (" (policy) skipping rule for different error name\n"); continue; @@ -914,8 +917,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, if (rule->d.receive.interface != NULL) { - if (!dbus_message_has_interface (message, - rule->d.receive.interface)) + if (dbus_message_get_interface (message) == NULL || + strcmp (dbus_message_get_interface (message), + rule->d.receive.interface) != 0) { _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; @@ -923,8 +927,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, } else if (rule->d.receive.member != NULL) { - if (!dbus_message_has_member (message, - rule->d.receive.member)) + if (dbus_message_get_member (message) == NULL || + strcmp (dbus_message_get_member (message), + rule->d.receive.member) != 0) { _dbus_verbose (" (policy) skipping rule for different member\n"); continue; @@ -932,8 +937,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, } else if (rule->d.receive.error != NULL) { - if (!dbus_message_has_error_name (message, - rule->d.receive.error)) + if (dbus_message_get_error_name (message) == NULL || + strcmp (dbus_message_get_error_name (message), + rule->d.receive.error) != 0) { _dbus_verbose (" (policy) skipping rule for different error name\n"); continue; diff --git a/bus/test.c b/bus/test.c index d28d7edf..1f13e4b6 100644 --- a/bus/test.c +++ b/bus/test.c @@ -107,8 +107,9 @@ client_disconnect_handler (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - if (!dbus_message_has_name (message, - DBUS_MESSAGE_LOCAL_DISCONNECT)) + if (!dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; _dbus_verbose ("Removing client %p in disconnect handler\n", 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 diff --git a/doc/TODO b/doc/TODO index 75ba7d86..843d4e15 100644 --- a/doc/TODO +++ b/doc/TODO @@ -23,9 +23,6 @@ (changing get_string to have an error return, and allowing a type error as a possible return) - - We might consider returning a "no such operation" error in dbus-connection.c - for unhandled messages. - - The convenience functions in dbus-bus.h should perhaps have the signatures that they would have if they were autogenerated stubs. e.g. the acquire service function. We should also evaluate diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c index d4b5f9b2..6b057078 100644 --- a/glib/test-dbus-glib.c +++ b/glib/test-dbus-glib.c @@ -30,8 +30,9 @@ main (int argc, char **argv) dbus_connection_setup_with_g_main (connection, NULL); - 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); dbus_error_init (&error); reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); @@ -42,7 +43,7 @@ main (int argc, char **argv) return 1; } - g_print ("reply name: %s\n", dbus_message_get_name (reply)); + g_print ("reply received\n"); g_main_loop_run (loop); diff --git a/glib/test-profile.c b/glib/test-profile.c index 852bd091..bd04dd9c 100644 --- a/glib/test-profile.c +++ b/glib/test-profile.c @@ -21,6 +21,11 @@ * */ +/* FIXME this test is wacky since both client and server keep + * sending each other method calls, but nobody sends + * a DBUS_MESSAGE_TYPE_METHOD_RETURN + */ + #include #include #include "dbus-glib.h" @@ -29,7 +34,9 @@ #define N_CLIENT_THREADS 1 #define N_ITERATIONS 1000 #define PAYLOAD_SIZE 30 -#define ECHO_MESSAGE "org.freedesktop.DBus.Test.EchoProfile" +#define ECHO_INTERFACE "org.freedekstop.EchoTest" +#define ECHO_METHOD "EchoProfile" + static const char *address; static unsigned char *payload; @@ -38,7 +45,7 @@ send_echo_message (DBusConnection *connection) { DBusMessage *message; - message = dbus_message_new_method_call (ECHO_MESSAGE, NULL); + message = dbus_message_new_method_call (ECHO_INTERFACE, ECHO_METHOD, NULL); dbus_message_append_args (message, DBUS_TYPE_STRING, "Hello World!", DBUS_TYPE_INT32, 123456, @@ -61,13 +68,15 @@ client_filter (DBusMessageHandler *handler, { int *iterations = user_data; - if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) { g_printerr ("Client thread disconnected\n"); exit (1); } - else if (dbus_message_has_name (message, - ECHO_MESSAGE)) + else if (dbus_message_is_method_call (message, + ECHO_INTERFACE, ECHO_METHOD)) { *iterations += 1; if (*iterations >= N_ITERATIONS) @@ -139,13 +148,16 @@ server_filter (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) { g_printerr ("Server thread disconnected\n"); exit (1); } - else if (dbus_message_has_name (message, - ECHO_MESSAGE)) + else if (dbus_message_is_method_call (message, + ECHO_INTERFACE, + ECHO_METHOD)) { send_echo_message (connection); return DBUS_HANDLER_RESULT_HANDLED; diff --git a/glib/test-thread-client.c b/glib/test-thread-client.c index a3290b27..8a1e44cb 100644 --- a/glib/test-thread-client.c +++ b/glib/test-thread-client.c @@ -19,7 +19,8 @@ thread_func (gpointer data) while (1) { - message = dbus_message_new_method_call ("org.freedesktop.ThreadTest", NULL); + message = dbus_message_new_method_call ("org.freedesktop.ThreadTest", + "TestMethod", NULL); dbus_message_append_iter_init (message, &iter); diff --git a/glib/test-thread-server.c b/glib/test-thread-server.c index 3ad1f907..33652f8c 100644 --- a/glib/test-thread-server.c +++ b/glib/test-thread-server.c @@ -43,7 +43,8 @@ handle_test_message (DBusMessageHandler *handler, GString *counter_str; int i; - if (!dbus_message_has_name (message, "org.freedesktop.ThreadTest")) + if (!dbus_message_is_method_call (message, "org.freedesktop.ThreadTest", + "TestMethod")) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; dbus_message_iter_init (message, &iter); @@ -145,7 +146,8 @@ handle_disconnect (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - if (!dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + if (!dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; g_print ("connection disconnected\n"); diff --git a/test/data/incomplete-messages/missing-body.message b/test/data/incomplete-messages/missing-body.message index 71ac5abc..69e371e0 100644 --- a/test/data/incomplete-messages/missing-body.message +++ b/test/data/incomplete-messages/missing-body.message @@ -1,9 +1,12 @@ ## message that's missing an expected body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' END_LENGTH Header ALIGN 8 diff --git a/test/data/invalid-messages/array-of-nil.message b/test/data/invalid-messages/array-of-nil.message index e86e6a10..4810d318 100644 --- a/test/data/invalid-messages/array-of-nil.message +++ b/test/data/invalid-messages/array-of-nil.message @@ -1,9 +1,14 @@ # Message with an array of NIL (not allowed) -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/invalid-messages/array-with-mixed-types.message b/test/data/invalid-messages/array-with-mixed-types.message index 763a6c29..1bdd549b 100644 --- a/test/data/invalid-messages/array-with-mixed-types.message +++ b/test/data/invalid-messages/array-with-mixed-types.message @@ -1,10 +1,15 @@ # Message with an array of array where the child arrays are of # different types -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/invalid-messages/bad-boolean-array.message b/test/data/invalid-messages/bad-boolean-array.message index c045b978..e4df1903 100644 --- a/test/data/invalid-messages/bad-boolean-array.message +++ b/test/data/invalid-messages/bad-boolean-array.message @@ -1,10 +1,15 @@ ## a message with an invalid boolean array ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/invalid-messages/bad-boolean.message b/test/data/invalid-messages/bad-boolean.message index 00a29626..7b518d57 100644 --- a/test/data/invalid-messages/bad-boolean.message +++ b/test/data/invalid-messages/bad-boolean.message @@ -1,10 +1,15 @@ ## a message with an invalid boolean value ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/invalid-messages/bad-endian.message b/test/data/invalid-messages/bad-endian.message index b1432359..c08f0188 100644 --- a/test/data/invalid-messages/bad-endian.message +++ b/test/data/invalid-messages/bad-endian.message @@ -4,10 +4,20 @@ BYTE 'i' BYTE 1 BYTE 0 BYTE 0 + LENGTH Header LENGTH Body -## client serial -INT32 7 + +FIELD_NAME ifce +TYPE STRING +STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + +ALIGN 8 + END_LENGTH Header + START_LENGTH Body END_LENGTH Body diff --git a/test/data/invalid-messages/local-namespace.message b/test/data/invalid-messages/local-namespace.message index ceb3053d..f485d70c 100644 --- a/test/data/invalid-messages/local-namespace.message +++ b/test/data/invalid-messages/local-namespace.message @@ -2,10 +2,15 @@ ## invalid ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce +TYPE STRING +STRING 'org.freedesktop.Local' +FIELD_NAME mebr TYPE STRING -STRING 'org.freedesktop.Local.Disconnect' +STRING 'Disconnected' + ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/invalid-messages/no-dot-in-name.message b/test/data/invalid-messages/no-dot-in-name.message index 4cde0d1f..53e288d0 100644 --- a/test/data/invalid-messages/no-dot-in-name.message +++ b/test/data/invalid-messages/no-dot-in-name.message @@ -1,10 +1,15 @@ -## a message with dotless name +## a message with dotless interface ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce +TYPE STRING +STRING 'NoDotInHere' +FIELD_NAME mebr TYPE STRING -STRING 'NoNamespaceHere' +STRING 'Bar' + ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/invalid-messages/not-nul-header-padding.message b/test/data/invalid-messages/not-nul-header-padding.message index 1172af4b..f98812c2 100644 --- a/test/data/invalid-messages/not-nul-header-padding.message +++ b/test/data/invalid-messages/not-nul-header-padding.message @@ -1,7 +1,15 @@ ## has one non-nul byte in header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER +VALID_HEADER method_call + +FIELD_NAME ifce +TYPE STRING +STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + FIELD_NAME unkn TYPE STRING STRING 'a' diff --git a/test/data/invalid-messages/overlong-name.message b/test/data/invalid-messages/overlong-name.message index 0fdc7bc9..4108a037 100644 --- a/test/data/invalid-messages/overlong-name.message +++ b/test/data/invalid-messages/overlong-name.message @@ -1,10 +1,15 @@ ## a message with too-long name field ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.foo.bar.this.is.really.long 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200' + +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/invalid-messages/too-little-header-padding.message b/test/data/invalid-messages/too-little-header-padding.message index cf73be68..f6e7af4b 100644 --- a/test/data/invalid-messages/too-little-header-padding.message +++ b/test/data/invalid-messages/too-little-header-padding.message @@ -1,7 +1,15 @@ ## has one byte missing from header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER +VALID_HEADER method_call + +FIELD_NAME ifce +TYPE STRING +STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + FIELD_NAME unkn TYPE STRING STRING 'a' diff --git a/test/data/invalid-messages/too-much-header-padding-by-far.message b/test/data/invalid-messages/too-much-header-padding-by-far.message index a60aca88..6cc5b391 100644 --- a/test/data/invalid-messages/too-much-header-padding-by-far.message +++ b/test/data/invalid-messages/too-much-header-padding-by-far.message @@ -1,7 +1,15 @@ ## has one byte extra header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER +VALID_HEADER method_call + +FIELD_NAME ifce +TYPE STRING +STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + FIELD_NAME unkn TYPE STRING STRING 'a' diff --git a/test/data/invalid-messages/too-much-header-padding.message b/test/data/invalid-messages/too-much-header-padding.message index ebf154eb..6cf004b9 100644 --- a/test/data/invalid-messages/too-much-header-padding.message +++ b/test/data/invalid-messages/too-much-header-padding.message @@ -1,7 +1,15 @@ ## has one byte extra header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER +VALID_HEADER method_call + +FIELD_NAME ifce +TYPE STRING +STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + FIELD_NAME unkn TYPE STRING STRING 'a' diff --git a/test/data/invalid-messages/too-short-dict.message b/test/data/invalid-messages/too-short-dict.message index ba200461..59621126 100644 --- a/test/data/invalid-messages/too-short-dict.message +++ b/test/data/invalid-messages/too-short-dict.message @@ -1,11 +1,18 @@ # Message with lots of different argument types -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' -END_LENGTH Header +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + ALIGN 8 + +END_LENGTH Header + START_LENGTH Body TYPE DICT LENGTH Dict diff --git a/test/data/valid-messages/array-of-array-of-uint32.message b/test/data/valid-messages/array-of-array-of-uint32.message index 82b8273d..4fea3d25 100644 --- a/test/data/valid-messages/array-of-array-of-uint32.message +++ b/test/data/valid-messages/array-of-array-of-uint32.message @@ -1,9 +1,12 @@ # Message with an array of array of uint32 -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/dict-simple.message b/test/data/valid-messages/dict-simple.message index 34fb47d9..9450ef14 100644 --- a/test/data/valid-messages/dict-simple.message +++ b/test/data/valid-messages/dict-simple.message @@ -1,9 +1,12 @@ # A simple dict -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/dict.message b/test/data/valid-messages/dict.message index 6b9d004e..6b15c627 100644 --- a/test/data/valid-messages/dict.message +++ b/test/data/valid-messages/dict.message @@ -1,9 +1,12 @@ # Dict with different values -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/emptiness.message b/test/data/valid-messages/emptiness.message index 87196b16..edc7a6cb 100644 --- a/test/data/valid-messages/emptiness.message +++ b/test/data/valid-messages/emptiness.message @@ -1,9 +1,12 @@ # Empty arrays and strings -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/lots-of-arguments.message b/test/data/valid-messages/lots-of-arguments.message index 6549646e..36cad4cd 100644 --- a/test/data/valid-messages/lots-of-arguments.message +++ b/test/data/valid-messages/lots-of-arguments.message @@ -1,9 +1,12 @@ # Message with lots of different argument types -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/no-padding.message b/test/data/valid-messages/no-padding.message index b47dca78..0241c364 100644 --- a/test/data/valid-messages/no-padding.message +++ b/test/data/valid-messages/no-padding.message @@ -1,11 +1,14 @@ ## Message with no header padding ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER +VALID_HEADER method_call -FIELD_NAME name +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' ## this byte array is filled with zeros to the natural length ## of the header diff --git a/test/data/valid-messages/opposite-endian.message b/test/data/valid-messages/opposite-endian.message index f8975b8b..b225f013 100644 --- a/test/data/valid-messages/opposite-endian.message +++ b/test/data/valid-messages/opposite-endian.message @@ -3,15 +3,14 @@ OPPOSITE_ENDIAN ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER +VALID_HEADER method_call -FIELD_NAME rply -TYPE UINT32 -UINT32 10000 - -FIELD_NAME name +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' FIELD_NAME unkn TYPE INT32 diff --git a/test/data/valid-messages/recursive-types.message b/test/data/valid-messages/recursive-types.message index 2ac6ad13..a8ef0441 100644 --- a/test/data/valid-messages/recursive-types.message +++ b/test/data/valid-messages/recursive-types.message @@ -1,11 +1,14 @@ ## Message with recursive types ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER +VALID_HEADER method_call -FIELD_NAME name +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message index f0ecccdd..533c1179 100644 --- a/test/data/valid-messages/simplest-manual.message +++ b/test/data/valid-messages/simplest-manual.message @@ -10,9 +10,14 @@ LENGTH Header LENGTH Body ## client serial INT32 7 -FIELD_NAME name + +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/simplest.message b/test/data/valid-messages/simplest.message index 7bb1872d..868d270e 100644 --- a/test/data/valid-messages/simplest.message +++ b/test/data/valid-messages/simplest.message @@ -1,10 +1,15 @@ ## simplest possible valid message ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call + +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' + ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/standard-acquire-service.message b/test/data/valid-messages/standard-acquire-service.message index 5056d8df..081473f0 100644 --- a/test/data/valid-messages/standard-acquire-service.message +++ b/test/data/valid-messages/standard-acquire-service.message @@ -1,9 +1,12 @@ # Standard org.freedesktop.DBus.AcquireService message -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING -STRING 'org.freedesktop.DBus.AcquireService' +STRING 'org.freedesktop.DBus' +FIELD_NAME mebr +TYPE STRING +STRING 'AcquireService' FIELD_NAME srvc TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-hello.message b/test/data/valid-messages/standard-hello.message index f3f65961..ed9ff9e7 100644 --- a/test/data/valid-messages/standard-hello.message +++ b/test/data/valid-messages/standard-hello.message @@ -1,9 +1,12 @@ # Standard org.freedesktop.DBus.Hello message -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING -STRING 'org.freedesktop.DBus.Hello' +STRING 'org.freedesktop.DBus' +FIELD_NAME mebr +TYPE STRING +STRING 'Hello' FIELD_NAME srvc TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-list-services.message b/test/data/valid-messages/standard-list-services.message index 9dfb72e3..9a6f1d87 100644 --- a/test/data/valid-messages/standard-list-services.message +++ b/test/data/valid-messages/standard-list-services.message @@ -1,9 +1,12 @@ # Standard org.freedesktop.DBus.ListServices message -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING -STRING 'org.freedesktop.DBus.ListServices' +STRING 'org.freedesktop.DBus' +FIELD_NAME mebr +TYPE STRING +STRING 'ListServices' FIELD_NAME srvc TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-service-exists.message b/test/data/valid-messages/standard-service-exists.message index 6755fea6..c53319b6 100644 --- a/test/data/valid-messages/standard-service-exists.message +++ b/test/data/valid-messages/standard-service-exists.message @@ -1,9 +1,12 @@ # Standard org.freedesktop.DBus.ServiceExists message -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING -STRING 'org.freedesktop.DBus.ServiceExists' +STRING 'org.freedesktop.DBus' +FIELD_NAME mebr +TYPE STRING +STRING 'ServiceExists' FIELD_NAME srvc TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/unknown-header-field.message b/test/data/valid-messages/unknown-header-field.message index 18ab379c..17ae116a 100644 --- a/test/data/valid-messages/unknown-header-field.message +++ b/test/data/valid-messages/unknown-header-field.message @@ -1,10 +1,13 @@ ## message with a 'name' header field and unknown 'unkn' field ## VALID_HEADER includes a LENGTH Header and LENGTH Body -VALID_HEADER -FIELD_NAME name +VALID_HEADER method_call +FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' +FIELD_NAME mebr +TYPE STRING +STRING 'Bar' FIELD_NAME unkn TYPE INT32 INT32 0xfeeb diff --git a/test/test-service.c b/test/test-service.c index fffe4187..533f94ae 100644 --- a/test/test-service.c +++ b/test/test-service.c @@ -77,10 +77,16 @@ filter_func (DBusMessageHandler *handler, DBusMessage *message, void *user_data) { - if (dbus_message_has_name (message, "org.freedesktop.DBus.TestSuiteEcho")) + if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "Echo")) return handle_echo (connection, message); - else if (dbus_message_has_name (message, "org.freedesktop.DBus.TestSuiteExit") || - dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + else if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "Exit") || + dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) { dbus_connection_disconnect (connection); quit (); diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c index a0f77407..c7293abb 100644 --- a/tools/dbus-monitor.c +++ b/tools/dbus-monitor.c @@ -37,7 +37,9 @@ handler_func (DBusMessageHandler *handler, { print_message (message); - if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) exit (0); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c index 7c5328da..43c41c73 100644 --- a/tools/dbus-print-message.c +++ b/tools/dbus-print-message.c @@ -48,12 +48,37 @@ print_message (DBusMessage *message) message_type = dbus_message_get_type (message); sender = dbus_message_get_sender (message); - - printf ("%s name=%s; sender=%s\n", - type_to_name (message_type), - dbus_message_get_name (message), - sender ? sender : "(no sender)"); - + + switch (message_type) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + case DBUS_MESSAGE_TYPE_SIGNAL: + printf ("%s interface=%s; member=%s; sender=%s\n", + type_to_name (message_type), + dbus_message_get_interface (message), + dbus_message_get_member (message), + sender ? sender : "(no sender)"); + break; + + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + printf ("%s; sender=%s\n", + type_to_name (message_type), + sender ? sender : "(no sender)"); + break; + + case DBUS_MESSAGE_TYPE_ERROR: + printf ("%s name=%s; sender=%s\n", + type_to_name (message_type), + dbus_message_get_error_name (message), + sender ? sender : "(no sender)"); + break; + + default: + printf ("Message of unknown type %d received\n", + message_type); + break; + } + dbus_message_iter_init (message, &iter); do diff --git a/tools/dbus-send.1 b/tools/dbus-send.1 index f71c4c6e..978ee2e7 100644 --- a/tools/dbus-send.1 +++ b/tools/dbus-send.1 @@ -42,12 +42,16 @@ byte, boolean. (D-BUS supports more types than these, but Here is an example invocation: .nf - dbus-send \-\-dest='org.freedesktop.ExampleService' \\ - org.freedesktop.ExampleMessage \\ + dbus-send \-\-dest='org.freedesktop.ExampleService' \\ + org.freedesktop.ExampleInterface.ExampleMethod \\ int32:47 string:'hello world' double:65.32 .fi +Note that the interface is separated from a method or signal +name by a dot, though in the actual protocol the interface +and the interface member are separate fields. + .SH OPTIONS The following options are supported: .TP diff --git a/tools/dbus-send.c b/tools/dbus-send.c index fb876b52..7ea49aac 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -44,7 +44,7 @@ main (int argc, char *argv[]) DBusMessageIter iter; int i; DBusBusType type = DBUS_BUS_SESSION; - const char *dest = DBUS_SERVICE_BROADCAST; + const char *dest = DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST; char *name = NULL; int message_type = DBUS_MESSAGE_TYPE_SIGNAL; const char *type_str = NULL; @@ -106,11 +106,35 @@ main (int argc, char *argv[]) if (message_type == DBUS_MESSAGE_TYPE_METHOD_CALL) { - message = dbus_message_new_method_call (name, NULL); + char *last_dot; + + last_dot = strrchr (name, '.'); + if (last_dot == NULL) + { + fprintf (stderr, "Must use org.mydomain.Interface.Method notation, no dot in \"%s\"\n", + name); + exit (1); + } + *last_dot = '\0'; + + message = dbus_message_new_method_call (name, + last_dot + 1, + NULL); } else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL) { - message = dbus_message_new_signal (name); + char *last_dot; + + last_dot = strrchr (name, '.'); + if (last_dot == NULL) + { + fprintf (stderr, "Must use org.mydomain.Interface.Signal notation, no dot in \"%s\"\n", + name); + exit (1); + } + *last_dot = '\0'; + + message = dbus_message_new_signal (name, last_dot + 1); } else { -- cgit v1.2.1 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 --- ChangeLog | 16 +++++++++ bus/dispatch.c | 41 +++++++++++++++------- bus/policy.c | 35 +++++++++--------- bus/session.conf.in | 4 +-- bus/system.conf.in | 8 ++--- dbus/dbus-message.c | 7 ++-- .../debug-allow-all-sha1.conf.in | 4 +-- .../valid-config-files/debug-allow-all.conf.in | 4 +-- test/data/valid-config-files/system.d/test.conf | 4 +-- 9 files changed, 78 insertions(+), 45 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4a2d6a88..b5b37d1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +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 + 2003-08-18 Havoc Pennington * dbus/dbus-hash.c (_dbus_hash_table_insert_two_strings): fix diff --git a/bus/dispatch.c b/bus/dispatch.c index 8eda2500..16102aa0 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -418,11 +418,14 @@ pop_message_waiting_for_memory (DBusConnection *connection) } static void -warn_unexpected (DBusConnection *connection, - DBusMessage *message, - const char *expected) +warn_unexpected_real (DBusConnection *connection, + DBusMessage *message, + const char *expected, + const char *function, + int line) { - _dbus_warn ("Received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n", + _dbus_warn ("%s:%d received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n", + function, line, dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "(unset)", dbus_message_get_member (message) ? @@ -433,6 +436,23 @@ warn_unexpected (DBusConnection *connection, expected); } +#define warn_unexpected(connection, message, expected) \ + warn_unexpected_real (connection, message, expected, _DBUS_FUNCTION_NAME, __LINE__) + +static void +verbose_message_received (DBusConnection *connection, + DBusMessage *message) +{ + _dbus_verbose ("Received message interface \"%s\" member \"%s\" error name \"%s\" on %p\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + connection); +} + typedef struct { const char *expected_service_name; @@ -748,8 +768,7 @@ check_hello_message (BusContext *context, goto out; } - _dbus_verbose ("Received message %p on %p\n", - message, connection); + verbose_message_received (connection, message); if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) { @@ -984,8 +1003,7 @@ check_nonexistent_service_activation (BusContext *context, goto out; } - _dbus_verbose ("Received message %p on %p\n", - message, connection); + verbose_message_received (connection, message); if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { @@ -1542,8 +1560,8 @@ check_existent_service_activation (BusContext *context, goto out; } - _dbus_verbose ("Received message %p on %p after sending %s\n", - message, connection, "ActivateService"); + verbose_message_received (connection, message); + _dbus_verbose (" (after sending %s)\n", "ActivateService"); if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { @@ -1748,8 +1766,7 @@ check_segfault_service_activation (BusContext *context, goto out; } - _dbus_verbose ("Received message %p on %p\n", - message, connection); + verbose_message_received (connection, message); if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) { diff --git a/bus/policy.c b/bus/policy.c index 04ea4230..f7978c05 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -801,7 +801,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, if (rule->d.send.interface != NULL) { - if (dbus_message_get_interface (message) == NULL || + if (dbus_message_get_interface (message) != NULL && strcmp (dbus_message_get_interface (message), rule->d.send.interface) != 0) { @@ -809,9 +809,10 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, continue; } } - else if (rule->d.send.member != NULL) + + if (rule->d.send.member != NULL) { - if (dbus_message_get_member (message) == NULL || + if (dbus_message_get_member (message) != NULL && strcmp (dbus_message_get_member (message), rule->d.send.member) != 0) { @@ -819,9 +820,10 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, continue; } } - else if (rule->d.send.error != NULL) + + if (rule->d.send.error != NULL) { - if (dbus_message_get_error_name (message) == NULL || + if (dbus_message_get_error_name (message) != NULL && strcmp (dbus_message_get_error_name (message), rule->d.send.error) != 0) { @@ -902,32 +904,28 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, { BusPolicyRule *rule = link->data; - link = _dbus_list_get_next_link (&policy->rules, link); - - /* Rule is skipped if it specifies a different - * message name from the message, or a different - * origin from the message - */ + link = _dbus_list_get_next_link (&policy->rules, link); if (rule->type != BUS_POLICY_RULE_RECEIVE) { _dbus_verbose (" (policy) skipping non-receive rule\n"); continue; } - + if (rule->d.receive.interface != NULL) { - if (dbus_message_get_interface (message) == NULL || + if (dbus_message_get_interface (message) != NULL && strcmp (dbus_message_get_interface (message), rule->d.receive.interface) != 0) { _dbus_verbose (" (policy) skipping rule for different interface\n"); continue; } - } - else if (rule->d.receive.member != NULL) + } + + if (rule->d.receive.member != NULL) { - if (dbus_message_get_member (message) == NULL || + if (dbus_message_get_member (message) != NULL && strcmp (dbus_message_get_member (message), rule->d.receive.member) != 0) { @@ -935,9 +933,10 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, continue; } } - else if (rule->d.receive.error != NULL) + + if (rule->d.receive.error != NULL) { - if (dbus_message_get_error_name (message) == NULL || + if (dbus_message_get_error_name (message) != NULL && strcmp (dbus_message_get_error_name (message), rule->d.receive.error) != 0) { diff --git a/bus/session.conf.in b/bus/session.conf.in index 673d8739..09dd250e 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -14,8 +14,8 @@ - - + + diff --git a/bus/system.conf.in b/bus/system.conf.in index bd454ff3..96513a75 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -34,16 +34,16 @@ - - + + - - + + - + - + -- cgit v1.2.1 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 --- ChangeLog | 11 + 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 + 9 files changed, 727 insertions(+), 2 deletions(-) create mode 100644 dbus/dbus-object-tree.c create mode 100644 dbus/dbus-object-tree.h diff --git a/ChangeLog b/ChangeLog index b5b37d1e..30217379 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +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 + 2003-08-19 Havoc Pennington * dbus/dbus-message.c (decode_string_field): support FIELD_SENDER 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 v1.2.1 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 --- ChangeLog | 17 + 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 +- glib/dbus-gproxy.c | 4 +- glib/dbus-gproxy.h | 4 +- 24 files changed, 171 insertions(+), 2671 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 diff --git a/ChangeLog b/ChangeLog index 30217379..6aa36760 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +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 + 2003-08-25 Havoc Pennington Just noticed that dbus_message_test is hosed, I wonder when I 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 diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 36f9724c..01a6b4b9 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -35,7 +35,7 @@ struct DBusGProxy DBusConnection *connection; char *service; char *interface; - DBusObjectID object_id; + char *path; }; #define LOCK_PROXY(proxy) (g_static_mutex_lock (&(proxy)->lock)) @@ -248,7 +248,7 @@ dbus_gproxy_send (DBusGProxy *proxy, { /* FIXME */ } - if (!dbus_object_id_is_null (&proxy->object_id)) + if (proxy->path) { /* FIXME */ } diff --git a/glib/dbus-gproxy.h b/glib/dbus-gproxy.h index f40ce8a0..4e8f3f60 100644 --- a/glib/dbus-gproxy.h +++ b/glib/dbus-gproxy.h @@ -42,8 +42,8 @@ DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connect const char *service_name, const char *interface_name, GError **error); -DBusGProxy* dbus_gproxy_new_for_object_id (DBusConnection *connection, - const DBusObjectID *object_id, +DBusGProxy* dbus_gproxy_new_for_object_path (DBusConnection *connection, + const char *path, const char *interface_name); DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, const char *interface_name); -- cgit v1.2.1 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 --- ChangeLog | 4 ++++ dbus/dbus-internals.h | 2 +- doc/TODO | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 6aa36760..489b1d51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-08-29 Havoc Pennington + + * dbus/dbus-internals.h: fix _DBUS_N_GLOBAL_LOCKS + 2003-08-28 Havoc Pennington purge DBusObjectID 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); diff --git a/doc/TODO b/doc/TODO index 843d4e15..4cd4eeb6 100644 --- a/doc/TODO +++ b/doc/TODO @@ -68,3 +68,11 @@ files; they have to be in the toplevel file. when loading a child file, we could just init its DBusLimits from the parent, then after parsing copy its DBusLimits back to the parent + + - when making a method call, if the call serial were globally unique, + we could forward the call serial along with any method calls made + as a result of the first method call, and allow reentrancy that was + strictly part of the call stack of said method call. But I don't + really see how to do this without making the user pass around the + call serial to all method calls all the time, or disallowing + async calls. -- cgit v1.2.1 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 --- ChangeLog | 9 + dbus/dbus-object-tree.c | 547 +++++++++++++++++++++++++++++++++++++----------- glib/dbus-gidl.c | 5 +- glib/dbus-gidl.h | 10 +- 4 files changed, 439 insertions(+), 132 deletions(-) diff --git a/ChangeLog b/ChangeLog index 489b1d51..8633080c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +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 + 2003-08-29 Havoc Pennington * dbus/dbus-internals.h: fix _DBUS_N_GLOBAL_LOCKS 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; diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index b6e0fb8c..c1a1f6dc 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -37,7 +37,6 @@ struct MethodInfo int refcount; GSList *args; char *name; - MethodStyle style; }; struct SignalInfo @@ -157,15 +156,13 @@ free_arg_list (GSList **args_p) } MethodInfo* -method_info_new (const char *name, - MethodStyle style) +method_info_new (const char *name) { MethodInfo *info; info = g_new0 (MethodInfo, 1); info->refcount = 1; info->name = g_strdup (name); - info->style = style; return info; } diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index c3c72d61..812e1866 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -40,13 +40,6 @@ typedef enum ARG_OUT } ArgDirection; -typedef enum -{ - METHOD_SYNC, - METHOD_ASYNC, - METHOD_CANCELLABLE -} MethodStyle; - InterfaceInfo* interface_info_new (const char *name); void interface_info_ref (InterfaceInfo *info); void interface_info_unref (InterfaceInfo *info); @@ -57,8 +50,7 @@ void interface_info_add_method (InterfaceInfo *info, void interface_info_add_signal (InterfaceInfo *info, SignalInfo *signal); -MethodInfo* method_info_new (const char *name, - MethodStyle style); +MethodInfo* method_info_new (const char *name); void method_info_ref (MethodInfo *info); void method_info_unref (MethodInfo *info); -- cgit v1.2.1 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 --- ChangeLog | 4 + dbus/dbus-object-tree.c | 303 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 283 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8633080c..0c20af41 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-08-30 Havoc Pennington + + * dbus/dbus-object-tree.c: write tests and fix the discovered bugs + 2003-08-29 Havoc Pennington * dbus/dbus-object-tree.c: modify to allow overlapping paths to be 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 v1.2.1 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 --- ChangeLog | 21 + bus/dispatch.c | 35 +- bus/driver.c | 12 +- 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 +- doc/TODO | 3 + glib/dbus-gidl.c | 6 - glib/dbus-gidl.h | 1 - glib/test-dbus-glib.c | 7 +- glib/test-profile.c | 6 +- glib/test-thread-client.c | 6 +- test/data/valid-config-files/system.d/test.conf | 4 +- .../array-of-array-of-uint32.message | 7 +- test/data/valid-messages/dict-simple.message | 7 +- test/data/valid-messages/dict.message | 7 +- test/data/valid-messages/emptiness.message | 7 +- test/data/valid-messages/lots-of-arguments.message | 7 +- test/data/valid-messages/no-padding.message | 7 +- test/data/valid-messages/opposite-endian.message | 7 +- test/data/valid-messages/recursive-types.message | 7 +- test/data/valid-messages/simplest-manual.message | 3 + test/data/valid-messages/simplest.message | 8 +- .../standard-acquire-service.message | 3 + test/data/valid-messages/standard-hello.message | 3 + .../valid-messages/standard-list-services.message | 3 + .../valid-messages/standard-service-exists.message | 3 + .../valid-messages/unknown-header-field.message | 7 +- tools/dbus-send.1 | 18 +- tools/dbus-send.c | 22 +- 39 files changed, 1362 insertions(+), 722 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0c20af41..a31c1680 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +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 + 2003-08-30 Havoc Pennington * dbus/dbus-object-tree.c: write tests and fix the discovered bugs diff --git a/bus/dispatch.c b/bus/dispatch.c index 16102aa0..2f2e9e9d 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -727,9 +727,10 @@ check_hello_message (BusContext *context, acquired = NULL; message = NULL; - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "Hello", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello"); if (message == NULL) return TRUE; @@ -958,9 +959,10 @@ check_nonexistent_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "ActivateService", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService"); if (message == NULL) return TRUE; @@ -1341,9 +1343,10 @@ check_send_exit_to_service (BusContext *context, retval = FALSE; /* Kill off the test service by sending it a quit message */ - message = dbus_message_new_method_call ("org.freedesktop.TestSuite", - "Exit", - service_name); + message = dbus_message_new_method_call (service_name, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Exit"); if (message == NULL) { @@ -1510,9 +1513,10 @@ check_existent_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "ActivateService", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService"); if (message == NULL) return TRUE; @@ -1720,9 +1724,10 @@ check_segfault_service_activation (BusContext *context, dbus_error_init (&error); - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "ActivateService", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService"); if (message == NULL) return TRUE; diff --git a/bus/driver.c b/bus/driver.c index 7fd9cd87..61bfe1c5 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -49,7 +49,8 @@ bus_driver_send_service_deleted (const char *service_name, _dbus_verbose ("sending service deleted: %s\n", service_name); - message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, "ServiceDeleted"); if (message == NULL) @@ -84,7 +85,8 @@ bus_driver_send_service_created (const char *service_name, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, "ServiceCreated"); if (message == NULL) @@ -125,7 +127,8 @@ bus_driver_send_service_lost (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, "ServiceLost"); if (message == NULL) @@ -167,7 +170,8 @@ bus_driver_send_service_acquired (DBusConnection *connection, _DBUS_ASSERT_ERROR_IS_CLEAR (error); - message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, "ServiceAcquired"); if (message == NULL) diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 89a2d12b..a38b4a26 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -403,10 +403,10 @@ dbus_bus_register (DBusConnection *connection, return TRUE; } - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "Hello", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); - + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello"); if (!message) { @@ -522,9 +522,10 @@ dbus_bus_acquire_service (DBusConnection *connection, _dbus_return_val_if_fail (service_name != NULL, 0); _dbus_return_val_if_error_is_set (error, 0); - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "AcquireService", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "AcquireService"); if (message == NULL) { @@ -596,9 +597,10 @@ dbus_bus_service_exists (DBusConnection *connection, _dbus_return_val_if_fail (service_name != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "ServiceExists", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ServiceExists"); if (message == NULL) { _DBUS_SET_OOM (error); @@ -659,9 +661,10 @@ dbus_bus_activate_service (DBusConnection *connection, DBusMessage *msg; DBusMessage *reply; - msg = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "ActivateService", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "ActivateService"); if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name, DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID)) diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 0c384594..86678673 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -825,7 +825,8 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (io_path_cond == NULL) goto error; - disconnect_message = dbus_message_new_signal (DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + disconnect_message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_LOCAL, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected"); if (disconnect_message == NULL) @@ -2522,7 +2523,7 @@ dbus_connection_dispatch (DBusConnection *connection) /* We're still protected from dispatch() reentrancy here * since we acquired the dispatcher */ - _dbus_verbose (" running object handler on message %p (%s)\n", + _dbus_verbose (" running object path dispatch on message %p (%s)\n", message, dbus_message_get_interface (message) ? dbus_message_get_interface (message) : diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 12ad0682..0b346530 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -200,7 +200,6 @@ void dbus_connection_send_preallocated (DBusConnection /* Object tree functionality */ typedef void (* DBusObjectPathUnregisterFunction) (DBusConnection *connection, - const char **path, void *user_data); typedef DBusHandlerResult (* DBusObjectPathMessageFunction) (DBusConnection *connection, DBusMessage *message, diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 449dd33a..6343056e 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -871,8 +871,6 @@ _dbus_marshal_string_array (DBusString *str, /** * Marshals an object path value. - * - * @todo implement this function * * @param str the string to append the marshalled value to * @param byte_order the byte order to use @@ -886,7 +884,41 @@ _dbus_marshal_object_path (DBusString *str, const char **path, int path_len) { + int array_start, old_string_len; + int i; + + old_string_len = _dbus_string_get_length (str); + + /* Set the length to 0 temporarily */ + if (!_dbus_marshal_uint32 (str, byte_order, 0)) + goto nomem; + + array_start = _dbus_string_get_length (str); + + i = 0; + while (i < path_len) + { + if (!_dbus_string_append_byte (str, '/')) + goto nomem; + + if (!_dbus_string_append (str, path[0])) + goto nomem; + + ++i; + } + + /* Write the length now that we know it */ + _dbus_marshal_set_uint32 (str, byte_order, + _DBUS_ALIGN_VALUE (old_string_len, sizeof(dbus_uint32_t)), + _dbus_string_get_length (str) - array_start); + return TRUE; + + nomem: + /* Restore the previous length */ + _dbus_string_set_length (str, old_string_len); + + return FALSE; } static dbus_uint32_t @@ -1438,10 +1470,10 @@ _dbus_demarshal_string_array (const DBusString *str, return FALSE; } +#define VERBOSE_DECOMPOSE 0 + /** * Demarshals an object path. - * - * @todo implement this function * * @param str the string containing the data * @param byte_order the byte order @@ -1458,7 +1490,82 @@ _dbus_demarshal_object_path (const DBusString *str, char ***path, int *path_len) { + int len; + char **retval; + const char *data; + int n_components; + int i, j, comp; + + len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos); + data = _dbus_string_get_const_data_len (str, pos, len + 1); + _dbus_assert (data != NULL); + +#if VERBOSE_DECOMPOSE + _dbus_verbose ("Decomposing path \"%s\"\n", + data); +#endif + + n_components = 0; + i = 0; + while (i < len) + { + if (data[i] == '/') + n_components += 1; + ++i; + } + + retval = dbus_new0 (char*, n_components + 1); + + if (retval == NULL) + return FALSE; + + comp = 0; + i = 0; + while (i < len) + { + if (data[i] == '/') + ++i; + j = i; + + while (j < len && data[j] != '/') + ++j; + + /* Now [i, j) is the path component */ + _dbus_assert (i < j); + _dbus_assert (data[i] != '/'); + _dbus_assert (j == len || data[j] == '/'); + +#if VERBOSE_DECOMPOSE + _dbus_verbose (" (component in [%d,%d))\n", + i, j); +#endif + + retval[comp] = _dbus_memdup (&data[i], j - i + 1); + if (retval[comp] == NULL) + { + dbus_free_string_array (retval); + return FALSE; + } + retval[comp][j-i] = '\0'; +#if VERBOSE_DECOMPOSE + _dbus_verbose (" (component %d = \"%s\")\n", + comp, retval[comp]); +#endif + + ++comp; + i = j; + } + _dbus_assert (i == len); + _dbus_assert (retval[0] != NULL); + + *path = retval; + if (path_len) + *path_len = n_components; + if (new_pos) + *new_pos = pos + len + 1; + + return TRUE; } /** @@ -1514,6 +1621,7 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str, *end_pos = _DBUS_ALIGN_VALUE (pos, 8) + 8; break; + case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_STRING: { int len; @@ -1540,8 +1648,7 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str, *end_pos = pos + len; } break; - - case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_ARRAY: { int len; @@ -1917,6 +2024,7 @@ _dbus_marshal_validate_arg (const DBusString *str, } break; + case DBUS_TYPE_OBJECT_PATH: case DBUS_TYPE_STRING: { int len; @@ -1930,6 +2038,12 @@ _dbus_marshal_validate_arg (const DBusString *str, if (!validate_string (str, pos, len, end_pos)) return FALSE; + + if (type == DBUS_TYPE_OBJECT_PATH) + { + if (!_dbus_string_validate_path (str, pos, len)) + return FALSE; + } } break; @@ -2521,7 +2635,6 @@ _dbus_marshal_test (void) s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL); _dbus_assert (strcmp (s, "Hello") == 0); dbus_free (s); - _dbus_string_free (&str); diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index f779c8c1..6d162310 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -288,6 +288,56 @@ message_type_from_string (const DBusString *str, return -1; } +static dbus_bool_t +append_string_field (DBusString *dest, + int endian, + const char *field_name, + int type, + const char *value) +{ + int len; + + if (!_dbus_string_align_length (dest, 4)) + { + _dbus_warn ("could not align field name\n"); + return FALSE; + } + + if (!_dbus_string_append (dest, field_name)) + { + _dbus_warn ("couldn't append field name\n"); + return FALSE; + } + + if (!_dbus_string_append_byte (dest, type)) + { + _dbus_warn ("could not append typecode byte\n"); + return FALSE; + } + + len = strlen (value); + + if (!_dbus_marshal_uint32 (dest, endian, len)) + { + _dbus_warn ("couldn't append string length\n"); + return FALSE; + } + + if (!_dbus_string_append (dest, value)) + { + _dbus_warn ("couldn't append field value\n"); + return FALSE; + } + + if (!_dbus_string_append_byte (dest, 0)) + { + _dbus_warn ("couldn't append string nul term\n"); + return FALSE; + } + + return TRUE; +} + /** * Reads the given filename, which should be in "message description * language" (look at some examples), and builds up the message data @@ -298,6 +348,7 @@ message_type_from_string (const DBusString *str, * The file format is: * @code * VALID_HEADER 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"); diff --git a/doc/TODO b/doc/TODO index 4cd4eeb6..26e85a3e 100644 --- a/doc/TODO +++ b/doc/TODO @@ -76,3 +76,6 @@ really see how to do this without making the user pass around the call serial to all method calls all the time, or disallowing async calls. + + - the invalid messages in the test suite are all useless because + they are invalid for the wrong reasons due to protocol changes diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index c1a1f6dc..d64e95a7 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -197,12 +197,6 @@ method_info_get_args (MethodInfo *info) return info->args; } -MethodStyle -method_info_get_style (MethodInfo *info) -{ - return info->style; -} - void method_info_add_arg (MethodInfo *info, ArgInfo *arg) diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 812e1866..68649cf3 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -56,7 +56,6 @@ void method_info_unref (MethodInfo *info); const char* method_info_get_name (MethodInfo *info); GSList* method_info_get_args (MethodInfo *info); -MethodStyle method_info_get_style (MethodInfo *info); void method_info_add_arg (MethodInfo *info, ArgInfo *arg); diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c index 6b057078..beda0a7a 100644 --- a/glib/test-dbus-glib.c +++ b/glib/test-dbus-glib.c @@ -30,9 +30,10 @@ main (int argc, char **argv) dbus_connection_setup_with_g_main (connection, NULL); - message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "Hello", - DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello"); dbus_error_init (&error); reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); diff --git a/glib/test-profile.c b/glib/test-profile.c index bd04dd9c..3eac1618 100644 --- a/glib/test-profile.c +++ b/glib/test-profile.c @@ -34,7 +34,8 @@ #define N_CLIENT_THREADS 1 #define N_ITERATIONS 1000 #define PAYLOAD_SIZE 30 -#define ECHO_INTERFACE "org.freedekstop.EchoTest" +#define ECHO_PATH "/org/freedesktop/EchoTest" +#define ECHO_INTERFACE "org.freedesktop.EchoTest" #define ECHO_METHOD "EchoProfile" static const char *address; @@ -45,7 +46,8 @@ send_echo_message (DBusConnection *connection) { DBusMessage *message; - message = dbus_message_new_method_call (ECHO_INTERFACE, ECHO_METHOD, NULL); + message = dbus_message_new_method_call (NULL, ECHO_PATH, + ECHO_INTERFACE, ECHO_METHOD); dbus_message_append_args (message, DBUS_TYPE_STRING, "Hello World!", DBUS_TYPE_INT32, 123456, diff --git a/glib/test-thread-client.c b/glib/test-thread-client.c index 8a1e44cb..d51d4e6a 100644 --- a/glib/test-thread-client.c +++ b/glib/test-thread-client.c @@ -19,8 +19,10 @@ thread_func (gpointer data) while (1) { - message = dbus_message_new_method_call ("org.freedesktop.ThreadTest", - "TestMethod", NULL); + message = dbus_message_new_method_call (NULL, + "/org/freedesktop/ThreadTest", + "org.freedesktop.ThreadTest", + "TestMethod"); dbus_message_append_iter_init (message, &iter); diff --git a/test/data/valid-config-files/system.d/test.conf b/test/data/valid-config-files/system.d/test.conf index 3d1b2f54..10a79847 100644 --- a/test/data/valid-config-files/system.d/test.conf +++ b/test/data/valid-config-files/system.d/test.conf @@ -5,9 +5,9 @@ policy so that a particular user can own a service, and other connections can get messages from it --> - - + diff --git a/test/data/valid-messages/array-of-array-of-uint32.message b/test/data/valid-messages/array-of-array-of-uint32.message index 4fea3d25..692eca06 100644 --- a/test/data/valid-messages/array-of-array-of-uint32.message +++ b/test/data/valid-messages/array-of-array-of-uint32.message @@ -1,12 +1,7 @@ # Message with an array of array of uint32 VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/dict-simple.message b/test/data/valid-messages/dict-simple.message index 9450ef14..6986d439 100644 --- a/test/data/valid-messages/dict-simple.message +++ b/test/data/valid-messages/dict-simple.message @@ -1,12 +1,7 @@ # A simple dict VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/dict.message b/test/data/valid-messages/dict.message index 6b15c627..0f997b1f 100644 --- a/test/data/valid-messages/dict.message +++ b/test/data/valid-messages/dict.message @@ -1,12 +1,7 @@ # Dict with different values VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/emptiness.message b/test/data/valid-messages/emptiness.message index edc7a6cb..dbf531ca 100644 --- a/test/data/valid-messages/emptiness.message +++ b/test/data/valid-messages/emptiness.message @@ -1,12 +1,7 @@ # Empty arrays and strings VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/lots-of-arguments.message b/test/data/valid-messages/lots-of-arguments.message index 36cad4cd..993755ab 100644 --- a/test/data/valid-messages/lots-of-arguments.message +++ b/test/data/valid-messages/lots-of-arguments.message @@ -1,12 +1,7 @@ # Message with lots of different argument types VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS END_LENGTH Header ALIGN 8 START_LENGTH Body diff --git a/test/data/valid-messages/no-padding.message b/test/data/valid-messages/no-padding.message index 0241c364..e6d27d9d 100644 --- a/test/data/valid-messages/no-padding.message +++ b/test/data/valid-messages/no-padding.message @@ -3,12 +3,7 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS ## this byte array is filled with zeros to the natural length ## of the header diff --git a/test/data/valid-messages/opposite-endian.message b/test/data/valid-messages/opposite-endian.message index b225f013..c638b7b0 100644 --- a/test/data/valid-messages/opposite-endian.message +++ b/test/data/valid-messages/opposite-endian.message @@ -5,12 +5,7 @@ OPPOSITE_ENDIAN ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS FIELD_NAME unkn TYPE INT32 diff --git a/test/data/valid-messages/recursive-types.message b/test/data/valid-messages/recursive-types.message index a8ef0441..192fd9b7 100644 --- a/test/data/valid-messages/recursive-types.message +++ b/test/data/valid-messages/recursive-types.message @@ -3,12 +3,7 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message index 533c1179..9779234b 100644 --- a/test/data/valid-messages/simplest-manual.message +++ b/test/data/valid-messages/simplest-manual.message @@ -11,6 +11,9 @@ LENGTH Body ## client serial INT32 7 +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/foo' FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.Foo' diff --git a/test/data/valid-messages/simplest.message b/test/data/valid-messages/simplest.message index 868d270e..b9ddaf6b 100644 --- a/test/data/valid-messages/simplest.message +++ b/test/data/valid-messages/simplest.message @@ -2,13 +2,7 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call - -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS ALIGN 8 END_LENGTH Header diff --git a/test/data/valid-messages/standard-acquire-service.message b/test/data/valid-messages/standard-acquire-service.message index 081473f0..f313061f 100644 --- a/test/data/valid-messages/standard-acquire-service.message +++ b/test/data/valid-messages/standard-acquire-service.message @@ -1,6 +1,9 @@ # Standard org.freedesktop.DBus.AcquireService message VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-hello.message b/test/data/valid-messages/standard-hello.message index ed9ff9e7..795ede74 100644 --- a/test/data/valid-messages/standard-hello.message +++ b/test/data/valid-messages/standard-hello.message @@ -1,6 +1,9 @@ # Standard org.freedesktop.DBus.Hello message VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-list-services.message b/test/data/valid-messages/standard-list-services.message index 9a6f1d87..4c9c7c66 100644 --- a/test/data/valid-messages/standard-list-services.message +++ b/test/data/valid-messages/standard-list-services.message @@ -1,6 +1,9 @@ # Standard org.freedesktop.DBus.ListServices message VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/standard-service-exists.message b/test/data/valid-messages/standard-service-exists.message index c53319b6..ce14811a 100644 --- a/test/data/valid-messages/standard-service-exists.message +++ b/test/data/valid-messages/standard-service-exists.message @@ -1,6 +1,9 @@ # Standard org.freedesktop.DBus.ServiceExists message VALID_HEADER method_call +FIELD_NAME path +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' FIELD_NAME ifce TYPE STRING STRING 'org.freedesktop.DBus' diff --git a/test/data/valid-messages/unknown-header-field.message b/test/data/valid-messages/unknown-header-field.message index 17ae116a..5d95f812 100644 --- a/test/data/valid-messages/unknown-header-field.message +++ b/test/data/valid-messages/unknown-header-field.message @@ -2,12 +2,7 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce -TYPE STRING -STRING 'org.freedesktop.Foo' -FIELD_NAME mebr -TYPE STRING -STRING 'Bar' +REQUIRED_FIELDS FIELD_NAME unkn TYPE INT32 INT32 0xfeeb diff --git a/tools/dbus-send.1 b/tools/dbus-send.1 index 978ee2e7..725507c0 100644 --- a/tools/dbus-send.1 +++ b/tools/dbus-send.1 @@ -8,7 +8,8 @@ dbus-send \- Send a message to a message bus .SH SYNOPSIS .PP .B dbus-send -[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply] [\-\-type=TYPE] [contents ...] +[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply] +[\-\-type=TYPE] [contents ...] .SH DESCRIPTION @@ -28,21 +29,22 @@ specified, \fIdbus-send\fP sends to the session bus. Nearly all uses of \fIdbus-send\fP must provide the \-\-dest argument which is the name of a service on the bus to send the message to. If \-\-dest is omitted, a default service name of -"org.freedesktop.DBus.Broadcast" is used. +"org.freedesktop.Broadcast" is used. .PP -The name of the message to send must always be specified. Following -arguments, if any, are the message contents (message arguments). -These are given as a type name, a colon, and then the value of the -argument. The possible type names are: string, int32, uint32, double, -byte, boolean. (D-BUS supports more types than these, but -\fIdbus-send\fP currently does not.) +The object path and the name of the message to send must always be +specified. Following arguments, if any, are the message contents +(message arguments). These are given as a type name, a colon, and +then the value of the argument. The possible type names are: string, +int32, uint32, double, byte, boolean. (D-BUS supports more types than +these, but \fIdbus-send\fP currently does not.) .PP Here is an example invocation: .nf dbus-send \-\-dest='org.freedesktop.ExampleService' \\ + /org/freedesktop/sample/object/name \\ org.freedesktop.ExampleInterface.ExampleMethod \\ int32:47 string:'hello world' double:65.32 diff --git a/tools/dbus-send.c b/tools/dbus-send.c index 7ea49aac..67abe066 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -30,7 +30,7 @@ static void usage (char *name, int ecode) { - fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--type=TYPE] [--print-reply] [contents ...]\n", name); + fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--type=TYPE] [--print-reply] [contents ...]\n", name); exit (ecode); } @@ -45,11 +45,12 @@ main (int argc, char *argv[]) int i; DBusBusType type = DBUS_BUS_SESSION; const char *dest = DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST; - char *name = NULL; + const char *name = NULL; + const char *path = NULL; int message_type = DBUS_MESSAGE_TYPE_SIGNAL; const char *type_str = NULL; - if (argc < 2) + if (argc < 3) usage (argv[0], 1); print_reply = FALSE; @@ -72,8 +73,12 @@ main (int argc, char *argv[]) usage (argv[0], 0); else if (arg[0] == '-') usage (argv[0], 1); + else if (path == NULL) + path = arg; + else if (name == NULL) + name = arg; else - name = arg; + usage (argv[0], 1); } if (name == NULL) @@ -117,9 +122,10 @@ main (int argc, char *argv[]) } *last_dot = '\0'; - message = dbus_message_new_method_call (name, - last_dot + 1, - NULL); + message = dbus_message_new_method_call (NULL, + path, + name, + last_dot + 1); } else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL) { @@ -134,7 +140,7 @@ main (int argc, char *argv[]) } *last_dot = '\0'; - message = dbus_message_new_signal (name, last_dot + 1); + message = dbus_message_new_signal (path, name, last_dot + 1); } else { -- cgit v1.2.1 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 --- ChangeLog | 7 + bus/dispatch.c | 62 ++----- bus/test.c | 51 ++---- 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 - glib/test-profile.c | 23 +-- glib/test-thread-server.c | 52 +----- test/test-service.c | 15 +- tools/dbus-monitor.c | 11 +- 18 files changed, 184 insertions(+), 706 deletions(-) delete mode 100644 dbus/dbus-message-handler.c delete mode 100644 dbus/dbus-message-handler.h diff --git a/ChangeLog b/ChangeLog index a31c1680..4930c689 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-08-30 Havoc Pennington + + * dbus/dbus-connection.c: purge DBusMessageHandler + + * dbus/dbus-message-handler.c: remove DBusMessageHandler, just + use callbacks everywhere + 2003-08-30 Havoc Pennington * test/data/valid-config-files/system.d/test.conf: change to diff --git a/bus/dispatch.c b/bus/dispatch.c index 2f2e9e9d..7bdda0d4 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -32,8 +32,6 @@ #include #include -static dbus_int32_t message_handler_slot = -1; - typedef struct { BusContext *context; @@ -316,61 +314,21 @@ bus_dispatch (DBusConnection *connection, } static DBusHandlerResult -bus_dispatch_message_handler (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) +bus_dispatch_message_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) { return bus_dispatch (connection, message); } -static void -free_message_handler (void *data) -{ - DBusMessageHandler *handler = data; - - _dbus_assert (message_handler_slot >= 0); - - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&message_handler_slot); -} - dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection) -{ - DBusMessageHandler *handler; - - if (!dbus_connection_allocate_data_slot (&message_handler_slot)) +{ + if (!dbus_connection_add_filter (connection, + bus_dispatch_message_filter, + NULL, NULL)) return FALSE; - handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL); - if (handler == NULL) - { - dbus_connection_free_data_slot (&message_handler_slot); - return FALSE; - } - - if (!dbus_connection_add_filter (connection, handler)) - { - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&message_handler_slot); - - return FALSE; - } - - _dbus_assert (message_handler_slot >= 0); - - if (!dbus_connection_set_data (connection, - message_handler_slot, - handler, - free_message_handler)) - { - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&message_handler_slot); - - return FALSE; - } - return TRUE; } @@ -380,9 +338,9 @@ bus_dispatch_remove_connection (DBusConnection *connection) /* Here we tell the bus driver that we want to get off. */ bus_driver_remove_connection (connection); - dbus_connection_set_data (connection, - message_handler_slot, - NULL, NULL); + dbus_connection_remove_filter (connection, + bus_dispatch_message_filter, + NULL); } #ifdef DBUS_BUILD_TESTS diff --git a/bus/test.c b/bus/test.c index 1f13e4b6..b48ba0fe 100644 --- a/bus/test.c +++ b/bus/test.c @@ -102,10 +102,9 @@ remove_client_timeout (DBusTimeout *timeout, } static DBusHandlerResult -client_disconnect_handler (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) +client_disconnect_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) { if (!dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, @@ -128,35 +127,15 @@ client_disconnect_handler (DBusMessageHandler *handler, return DBUS_HANDLER_RESULT_HANDLED; } -static dbus_int32_t handler_slot = -1; - -static void -free_handler (void *data) -{ - DBusMessageHandler *handler = data; - - dbus_message_handler_unref (handler); - dbus_connection_free_data_slot (&handler_slot); -} - dbus_bool_t bus_setup_debug_client (DBusConnection *connection) { - DBusMessageHandler *disconnect_handler; - dbus_bool_t retval; - - disconnect_handler = dbus_message_handler_new (client_disconnect_handler, - NULL, NULL); - - if (disconnect_handler == NULL) - return FALSE; + dbus_bool_t retval; if (!dbus_connection_add_filter (connection, - disconnect_handler)) - { - dbus_message_handler_unref (disconnect_handler); - return FALSE; - } + client_disconnect_filter, + NULL, NULL)) + return FALSE; retval = FALSE; @@ -184,25 +163,15 @@ bus_setup_debug_client (DBusConnection *connection) if (!_dbus_list_append (&clients, connection)) goto out; - - if (!dbus_connection_allocate_data_slot (&handler_slot)) - goto out; - - /* Set up handler to be destroyed */ - if (!dbus_connection_set_data (connection, handler_slot, - disconnect_handler, - free_handler)) - { - dbus_connection_free_data_slot (&handler_slot); - goto out; - } retval = TRUE; out: if (!retval) { - dbus_message_handler_unref (disconnect_handler); /* unregisters it */ + dbus_connection_remove_filter (connection, + client_disconnect_filter, + NULL); dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL); 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 diff --git a/glib/test-profile.c b/glib/test-profile.c index 3eac1618..6d9d8e7f 100644 --- a/glib/test-profile.c +++ b/glib/test-profile.c @@ -63,8 +63,7 @@ send_echo_message (DBusConnection *connection) } static DBusHandlerResult -client_filter (DBusMessageHandler *handler, - DBusConnection *connection, +client_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { @@ -99,7 +98,6 @@ thread_func (void *data) DBusError error; GMainContext *context; GMainLoop *loop; - DBusMessageHandler *handler; DBusConnection *connection; int iterations; @@ -116,14 +114,9 @@ thread_func (void *data) iterations = 1; - handler = dbus_message_handler_new (client_filter, - &iterations, NULL); - if (!dbus_connection_add_filter (connection, - handler)) + client_filter, &iterations, NULL)) g_error ("no memory"); - - /* FIXME we leak the handler */ context = g_main_context_new (); loop = g_main_loop_new (context, FALSE); @@ -145,8 +138,7 @@ thread_func (void *data) } static DBusHandlerResult -server_filter (DBusMessageHandler *handler, - DBusConnection *connection, +server_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { @@ -172,17 +164,12 @@ static void new_connection_callback (DBusServer *server, DBusConnection *new_connection, void *user_data) -{ - DBusMessageHandler *handler; - +{ dbus_connection_ref (new_connection); dbus_connection_setup_with_g_main (new_connection, NULL); - - handler = dbus_message_handler_new (server_filter, - NULL, NULL); if (!dbus_connection_add_filter (new_connection, - handler)) + server_filter, NULL, NULL)) g_error ("no memory"); diff --git a/glib/test-thread-server.c b/glib/test-thread-server.c index 33652f8c..8898ca7f 100644 --- a/glib/test-thread-server.c +++ b/glib/test-thread-server.c @@ -25,13 +25,8 @@ thread_test_data_free (ThreadTestData *data) g_free (data); } -static DBusMessageHandler *disconnect_handler; -static DBusMessageHandler *filter_handler; -static dbus_int32_t handler_slot = -1; - static DBusHandlerResult -handle_test_message (DBusMessageHandler *handler, - DBusConnection *connection, +filter_test_message (DBusConnection *connection, DBusMessage *message, void *user_data) { @@ -132,17 +127,7 @@ handle_test_message (DBusMessageHandler *handler, } static DBusHandlerResult -handle_filter (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static DBusHandlerResult -handle_disconnect (DBusMessageHandler *handler, - DBusConnection *connection, +filter_disconnect (DBusConnection *connection, DBusMessage *message, void *user_data) { @@ -161,7 +146,6 @@ new_connection_callback (DBusServer *server, DBusConnection *new_connection, void *user_data) { - DBusMessageHandler *test_message_handler; ThreadTestData * data; g_print ("new_connection_callback\n"); @@ -171,26 +155,13 @@ new_connection_callback (DBusServer *server, data = thread_test_data_new (); - test_message_handler = - dbus_message_handler_new (handle_test_message, - data, (DBusFreeFunction)thread_test_data_free); - if (!dbus_connection_add_filter (new_connection, - test_message_handler)) - goto nomem; - - if (!dbus_connection_set_data (new_connection, - handler_slot, - test_message_handler, - (DBusFreeFunction)dbus_message_handler_unref)) + filter_test_message, data, + (DBusFreeFunction) thread_test_data_free)) goto nomem; if (!dbus_connection_add_filter (new_connection, - disconnect_handler)) - goto nomem; - - if (!dbus_connection_add_filter (new_connection, - filter_handler)) + filter_disconnect, NULL, NULL)) goto nomem; return; @@ -224,19 +195,6 @@ main (int argc, char *argv[]) dbus_error_free (&error); return 1; } - - if (!dbus_connection_allocate_data_slot (&handler_slot)) - g_error ("no memory for data slot"); - - filter_handler = - dbus_message_handler_new (handle_filter, NULL, NULL); - if (filter_handler == NULL) - g_error ("no memory for handler"); - - disconnect_handler = - dbus_message_handler_new (handle_disconnect, NULL, NULL); - if (disconnect_handler == NULL) - g_error ("no memory for handler"); dbus_server_set_new_connection_function (server, new_connection_callback, diff --git a/test/test-service.c b/test/test-service.c index 533f94ae..f22b1753 100644 --- a/test/test-service.c +++ b/test/test-service.c @@ -72,8 +72,7 @@ handle_echo (DBusConnection *connection, } static DBusHandlerResult -filter_func (DBusMessageHandler *handler, - DBusConnection *connection, +filter_func (DBusConnection *connection, DBusMessage *message, void *user_data) { @@ -104,7 +103,6 @@ main (int argc, { DBusConnection *connection; DBusError error; - DBusMessageHandler *handler; int result; dbus_error_init (&error); @@ -124,11 +122,8 @@ main (int argc, if (!test_connection_setup (loop, connection)) die ("No memory\n"); - handler = dbus_message_handler_new (filter_func, NULL, NULL); - if (handler == NULL) - die ("No memory"); - - if (!dbus_connection_add_filter (connection, handler)) + if (!dbus_connection_add_filter (connection, + filter_func, NULL, NULL)) die ("No memory"); result = dbus_bus_acquire_service (connection, "org.freedesktop.DBus.TestSuiteEchoService", @@ -145,10 +140,10 @@ main (int argc, _dbus_loop_run (loop); test_connection_shutdown (loop, connection); + + dbus_connection_remove_filter (connection, filter_func, NULL); dbus_connection_unref (connection); - - dbus_message_handler_unref (handler); _dbus_loop_unref (loop); loop = NULL; diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c index c7293abb..23ee346a 100644 --- a/tools/dbus-monitor.c +++ b/tools/dbus-monitor.c @@ -30,10 +30,9 @@ #include "dbus-print-message.h" static DBusHandlerResult -handler_func (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) +filter_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) { print_message (message); @@ -58,7 +57,6 @@ main (int argc, char *argv[]) DBusConnection *connection; DBusError error; DBusBusType type = DBUS_BUS_SESSION; - DBusMessageHandler *handler; GMainLoop *loop; int i; @@ -96,8 +94,7 @@ main (int argc, char *argv[]) dbus_connection_setup_with_g_main (connection, NULL); - handler = dbus_message_handler_new (handler_func, NULL, NULL); - dbus_connection_add_filter (connection, handler); + dbus_connection_add_filter (connection, filter_func, NULL, NULL); g_main_loop_run (loop); -- cgit v1.2.1 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 --- ChangeLog | 4 ++++ dbus/dbus-internals.c | 2 -- dbus/dbus-marshal.c | 6 ------ doc/dbus-specification.sgml | 7 +++++++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4930c689..5965b50a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-08-31 Havoc Pennington + + * fix build with --disable-tests + 2003-08-30 Havoc Pennington * dbus/dbus-connection.c: purge DBusMessageHandler 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 diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index 6c6f679a..031bb329 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -770,6 +770,13 @@ + + Authentication state diagrams + + + WRITEME + + Authentication mechanisms -- cgit v1.2.1 From 7b4ac5de11d90e9f7048f057d70d3da5104388b6 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 1 Sep 2003 18:02:06 +0000 Subject: 2003-09-01 Havoc Pennington * glib/Makefile.am: rearrange a bunch of files and get "make check" framework set up --- ChangeLog | 5 ++ doc/TODO | 3 ++ glib/Makefile.am | 30 ++++++++++-- glib/dbus-compiler-main.c | 48 ------------------ glib/dbus-glib-tool.c | 77 +++++++++++++++++++++++++++++ glib/dbus-gmain.c | 19 +++++++- glib/dbus-gparser.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ glib/dbus-gparser.h | 59 ++++++++++++++++++++++ 8 files changed, 308 insertions(+), 54 deletions(-) delete mode 100644 glib/dbus-compiler-main.c create mode 100644 glib/dbus-glib-tool.c create mode 100644 glib/dbus-gparser.c create mode 100644 glib/dbus-gparser.h diff --git a/ChangeLog b/ChangeLog index 5965b50a..f57c964a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-09-01 Havoc Pennington + + * glib/Makefile.am: rearrange a bunch of files and get "make + check" framework set up + 2003-08-31 Havoc Pennington * fix build with --disable-tests diff --git a/doc/TODO b/doc/TODO index 26e85a3e..6b308d39 100644 --- a/doc/TODO +++ b/doc/TODO @@ -79,3 +79,6 @@ - the invalid messages in the test suite are all useless because they are invalid for the wrong reasons due to protocol changes + + - Nuke the org.freedesktop.Broadcast service; instead, + just broadcast messages of type signal diff --git a/glib/Makefile.am b/glib/Makefile.am index 8cc09eb7..3d67db2f 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -11,18 +11,24 @@ dbusinclude_HEADERS= \ libdbus_glib_1_la_SOURCES = \ dbus-gmain.c \ dbus-gproxy.c \ + dbus-gtest.c \ + dbus-gtest.h \ dbus-gthread.c libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la -bin_PROGRAMS=dbus-glib-compiler +bin_PROGRAMS=dbus-glib-tool -dbus_glib_compiler_SOURCES = \ +dbus_glib_tool_SOURCES = \ dbus-gidl.c \ dbus-gidl.h \ - dbus-compiler-main.c + dbus-glib-tool.c \ + dbus-gparser.c \ + dbus-gparser.h \ + dbus-gtool-test.h -dbus_glib_compiler_LDADD= libdbus-glib-1.la $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la + +dbus_glib_tool_LDADD= libdbus-glib-1.la $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la if DBUS_BUILD_TESTS @@ -42,15 +48,29 @@ test_thread_client_SOURCES= \ test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la endif -noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS) +## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we +## build even when not doing "make check" +noinst_PROGRAMS= $(TESTS) test-dbus-glib $(THREAD_APPS) test_dbus_glib_SOURCES= \ test-dbus-glib.c test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la +## note that TESTS has special meaning (stuff to use in make check) +## so if adding tests not to be run in make check, don't add them to +## TESTS +TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus +TESTS=dbus-glib-test + +dbus_glib_test_SOURCES= \ + dbus-gtest-main.c + +dbus_glib_test_LDADD= $(top_builddir)/glib/libdbus-glib-1.la + else ### not building tests +TESTS= if HAVE_GLIB_THREADS noinst_PROGRAMS=test-profile diff --git a/glib/dbus-compiler-main.c b/glib/dbus-compiler-main.c deleted file mode 100644 index d8bf7bde..00000000 --- a/glib/dbus-compiler-main.c +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-compiler-main.c main() for GLib stubs/skels generator - * - * 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-gidl.h" - -int -main (int argc, char **argv) -{ - - - return 0; -} - -#ifdef DBUS_BUILD_TESTS - -/** - * @ingroup DBusGCompiler - * Unit test for GLib stubs/skels compiler - * @returns #TRUE on success. - */ -dbus_bool_t -_dbus_gcompiler_test (void) -{ - - return TRUE; -} - -#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-glib-tool.c b/glib/dbus-glib-tool.c new file mode 100644 index 00000000..aaf133d4 --- /dev/null +++ b/glib/dbus-glib-tool.c @@ -0,0 +1,77 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-compiler-main.c main() for GLib stubs/skels generator + * + * 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-gidl.h" +#include + +#ifdef DBUS_BUILD_TESTS +static void run_all_tests (const char *test_data_dir); +#endif + +int +main (int argc, char **argv) +{ + setlocale(LC_ALL, ""); + + return 0; +} + +#ifdef DBUS_BUILD_TESTS +static void +test_die (const char *failure) +{ + fprintf (stderr, "Unit test failed: %s\n", failure); + exit (1); +} + +static void +run_all_tests (const char *test_data_dir) +{ + if (test_data_dir == NULL) + test_data_dir = _dbus_getenv ("DBUS_TEST_DATA"); + + if (test_data_dir != NULL) + printf ("Test data in %s\n", test_data_dir); + else + printf ("No test data!\n"); + + printf ("%s: running gtool tests\n", "dbus-glib-tool"); + if (!_dbus_gtool_test (test_data_dir)) + test_die ("gtool"); + + printf ("%s: completed successfully\n", "dbus-glib-test"); +} + +/** + * @ingroup DBusGTool + * Unit test for GLib utility tool + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gtool_test (const char *test_data_dir) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index 9b14049d..36c6c6b4 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -21,8 +21,9 @@ * */ +#include #include "dbus-glib.h" -#include +#include "dbus-gtest.h" /** * @defgroup DBusGLib GLib bindings @@ -491,3 +492,19 @@ dbus_server_setup_with_g_main (DBusServer *server, } /** @} */ /* end of public API */ + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGLibInternals + * Unit test for GLib main loop integration + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gmain_test (const char *test_data_dir) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c new file mode 100644 index 00000000..6fea4abc --- /dev/null +++ b/glib/dbus-gparser.c @@ -0,0 +1,121 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gparser.c parse DBus description files + * + * 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-gparser.h" +#include "dbus-gidl.h" + +struct Parser +{ + int refcount; + +}; + +Parser* +parser_new (void) +{ + Parser *parser; + + parser = g_new0 (Parser, 1); + + parser->refcount = 1; + + return parser; +} + +void +parser_ref (Parser *parser) +{ + parser->refcount += 1; +} + +void +parser_unref (Parser *parser) +{ + parser->refcount -= 1; + if (parser->refcount == 0) + { + + + g_free (parser); + } +} + +gboolean +parser_check_doctype (Parser *parser, + const char *doctype, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL); + + if (strcmp (doctype, "dbus_description") != 0) + { + g_set_error (error, + G_MARKUP_ERROR_PARSE, + "D-BUS description file has the wrong document type %s, use dbus_description", + doctype); + return FALSE; + } + else + return TRUE; +} + +gboolean +parser_start_element (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL); + + return TRUE; +} + +gboolean +parser_end_element (Parser *parser, + const char *element_name, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL); + + return TRUE; +} + +gboolean +parser_content (Parser *parser, + const char *content, + int len, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL); + + return TRUE; +} + +gboolean +parser_finished (Parser *parser, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL); + + return TRUE; +} diff --git a/glib/dbus-gparser.h b/glib/dbus-gparser.h new file mode 100644 index 00000000..01339fbf --- /dev/null +++ b/glib/dbus-gparser.h @@ -0,0 +1,59 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gparser.h parse DBus description files + * + * 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_GLIB_PARSER_H +#define DBUS_GLIB_PARSER_H + +#include +#include + +G_BEGIN_DECLS + + +typedef struct Parser Parser; + +Parser* parser_new (void); +void parser_ref (Parser *parser); +void parser_unref (Parser *parser); +gboolean parser_check_doctype (Parser *parser, + const char *doctype, + GError **error); +gboolean parser_start_element (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error); +gboolean parser_end_element (Parser *parser, + const char *element_name, + GError **error); +gboolean parser_content (Parser *parser, + const char *content, + int len, + GError **error); +gboolean parser_finished (Parser *parser, + GError **error); + + + +G_END_DECLS + +#endif /* DBUS_GLIB_GPARSER_H */ -- cgit v1.2.1 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 --- ChangeLog | 9 + configure.in | 9 +- dbus/dbus-marshal.c | 4 +- dbus/dbus-protocol.h | 23 +- glib/Makefile.am | 6 +- glib/dbus-gidl.c | 90 +++++- glib/dbus-gidl.h | 10 + glib/dbus-glib.h | 26 +- glib/dbus-gloader-expat.c | 254 +++++++++++++++ glib/dbus-gobject.c | 780 ++++++++++++++++++++++++++++++++++++++++++++++ glib/dbus-gparser.c | 549 +++++++++++++++++++++++++++++++- glib/dbus-gparser.h | 8 +- 12 files changed, 1740 insertions(+), 28 deletions(-) create mode 100644 glib/dbus-gloader-expat.c create mode 100644 glib/dbus-gobject.c diff --git a/ChangeLog b/ChangeLog index f57c964a..d9557bed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +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 + 2003-09-01 Havoc Pennington * glib/Makefile.am: rearrange a bunch of files and get "make diff --git a/configure.in b/configure.in index 3963a5de..1125ef60 100644 --- a/configure.in +++ b/configure.in @@ -54,9 +54,11 @@ if test x$enable_verbose_mode = xyes; then fi if test x$enable_asserts = xno; then AC_DEFINE(DBUS_DISABLE_ASSERT,1,[Disable assertion checking]) + AC_DEFINE(G_DISABLE_ASSERT,1,[Disable GLib assertion macros]) fi if test x$enable_checks = xno; then AC_DEFINE(DBUS_DISABLE_CHECKS,1,[Disable public API sanity checking]) + AC_DEFINE(G_DISABLE_CHECKS,1,[Disable GLib public API sanity checking]) fi #### gcc warning flags @@ -545,7 +547,7 @@ AC_SUBST(DBUS_TEST_CFLAGS) AC_SUBST(DBUS_TEST_LIBS) # Glib detection -PKG_CHECK_MODULES(DBUS_GLIB, glib-2.0, have_glib=yes, have_glib=no) +PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0, have_glib=yes, have_glib=no) PKG_CHECK_MODULES(DBUS_GLIB_THREADS, glib-2.0 gthread-2.0, have_glib_threads=yes, have_glib_threads=no) if test x$have_glib = xno ; then @@ -570,6 +572,11 @@ AC_SUBST(DBUS_GLIB_CFLAGS) AC_SUBST(DBUS_GLIB_LIBS) AC_SUBST(DBUS_GLIB_THREADS_LIBS) +DBUS_GLIB_TOOL_CFLAGS=$XML_CFLAGS +DBUS_GLIB_TOOL_LIBS=$XML_LIBS +AC_SUBST(DBUS_GLIB_TOOL_CFLAGS) +AC_SUBST(DBUS_GLIB_TOOL_LIBS) + # Qt detection have_qt=no AC_MSG_CHECKING([for qglobal.h]) 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 diff --git a/glib/Makefile.am b/glib/Makefile.am index 3d67db2f..f3b43ed3 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION=1 +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) -DDBUS_COMPILATION=1 dbusincludedir=$(includedir)/dbus-1.0/dbus @@ -10,6 +10,7 @@ dbusinclude_HEADERS= \ libdbus_glib_1_la_SOURCES = \ dbus-gmain.c \ + dbus-gobject.c \ dbus-gproxy.c \ dbus-gtest.c \ dbus-gtest.h \ @@ -23,12 +24,13 @@ dbus_glib_tool_SOURCES = \ dbus-gidl.c \ dbus-gidl.h \ dbus-glib-tool.c \ + dbus-gloader-expat.c \ dbus-gparser.c \ dbus-gparser.h \ dbus-gtool-test.h -dbus_glib_tool_LDADD= libdbus-glib-1.la $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la +dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-glib-1.la $(top_builddir)/dbus/libdbus-1.la if DBUS_BUILD_TESTS diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index d64e95a7..12468abb 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -24,6 +24,13 @@ #include "dbus-gidl.h" +struct NodeInfo +{ + int refcount; + char *name; + GSList *interfaces; +}; + struct InterfaceInfo { int refcount; @@ -54,6 +61,20 @@ struct ArgInfo ArgDirection direction; }; +static void +free_interface_list (GSList **interfaces_p) +{ + GSList *tmp; + tmp = *interfaces_p; + while (tmp != NULL) + { + interface_info_unref (tmp->data); + tmp = tmp->next; + } + g_slist_free (*interfaces_p); + *interfaces_p = NULL; +} + static void free_method_list (GSList **methods_p) { @@ -82,6 +103,59 @@ free_signal_list (GSList **signals_p) *signals_p = NULL; } +NodeInfo* +node_info_new (const char *name) +{ + NodeInfo *info; + + /* name can be NULL */ + + info = g_new0 (NodeInfo, 1); + info->refcount = 1; + info->name = g_strdup (name); + + return info; +} + +void +node_info_ref (NodeInfo *info) +{ + info->refcount += 1; +} + +void +node_info_unref (NodeInfo *info) +{ + info->refcount -= 1; + if (info->refcount == 0) + { + free_interface_list (&info->interfaces); + g_free (info->name); + g_free (info); + } +} + +const char* +node_info_get_name (NodeInfo *info) +{ + return info->name; +} + +GSList* +node_info_get_interfaces (NodeInfo *info) +{ + return info->interfaces; +} + +void +node_info_add_interface (NodeInfo *info, + InterfaceInfo *interface) +{ + interface_info_ref (interface); + info->interfaces = g_slist_append (info->interfaces, interface); +} + + InterfaceInfo* interface_info_new (const char *name) { @@ -90,7 +164,7 @@ interface_info_new (const char *name) info = g_new0 (InterfaceInfo, 1); info->refcount = 1; info->name = g_strdup (name); - + return info; } @@ -113,6 +187,12 @@ interface_info_unref (InterfaceInfo *info) } } +const char* +interface_info_get_name (InterfaceInfo *info) +{ + return info->name; +} + GSList* interface_info_get_methods (InterfaceInfo *info) { @@ -163,7 +243,7 @@ method_info_new (const char *name) info = g_new0 (MethodInfo, 1); info->refcount = 1; info->name = g_strdup (name); - + return info; } @@ -213,7 +293,7 @@ signal_info_new (const char *name) info = g_new0 (SignalInfo, 1); info->refcount = 1; info->name = g_strdup (name); - + return info; } @@ -264,10 +344,12 @@ arg_info_new (const char *name, info = g_new0 (ArgInfo, 1); info->refcount = 1; + + /* name can be NULL */ info->name = g_strdup (name); info->direction = direction; info->type = type; - + return info; } diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 68649cf3..6e4e207a 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS +typedef struct NodeInfo NodeInfo; typedef struct InterfaceInfo InterfaceInfo; typedef struct MethodInfo MethodInfo; typedef struct SignalInfo SignalInfo; @@ -40,9 +41,18 @@ typedef enum ARG_OUT } ArgDirection; +NodeInfo* node_info_new (const char *name); +void node_info_ref (NodeInfo *info); +void node_info_unref (NodeInfo *info); +const char* node_info_get_name (NodeInfo *info); +GSList* node_info_get_interfaces (NodeInfo *info); +void node_info_add_interface (NodeInfo *info, + InterfaceInfo *interface); + InterfaceInfo* interface_info_new (const char *name); void interface_info_ref (InterfaceInfo *info); void interface_info_unref (InterfaceInfo *info); +const char* interface_info_get_name (InterfaceInfo *info); GSList* interface_info_get_methods (InterfaceInfo *info); GSList* interface_info_get_signals (InterfaceInfo *info); void interface_info_add_method (InterfaceInfo *info, diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 7ca22417..3a87dec2 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -24,7 +24,7 @@ #define DBUS_GLIB_H #include -#include +#include G_BEGIN_DECLS @@ -36,6 +36,30 @@ void dbus_connection_setup_with_g_main (DBusConnection *connection, void dbus_server_setup_with_g_main (DBusServer *server, GMainContext *context); +typedef struct DBusGObjectInfo DBusGObjectInfo; +typedef struct DBusGMethodInfo DBusGMethodInfo; + +struct DBusGMethodInfo +{ + GCallback function; + DBusHandleMessageFunction marshaller; + int data_offset; +}; + +struct DBusGObjectInfo +{ + const DBusGMethodInfo *infos; + const unsigned char *data; + void *dbus_internal_padding1; + void *dbus_internal_padding2; +}; + +void dbus_gobject_class_install_info (GObjectClass *object_class, + const DBusGObjectInfo *info); +void dbus_connection_register_gobject (DBusConnection *connection, + const char *at_path, + GObject *object); + #undef DBUS_INSIDE_DBUS_GLIB_H G_END_DECLS diff --git a/glib/dbus-gloader-expat.c b/glib/dbus-gloader-expat.c new file mode 100644 index 00000000..050d3532 --- /dev/null +++ b/glib/dbus-gloader-expat.c @@ -0,0 +1,254 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gloader-expat.c expat XML loader + * + * 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-gparser.h" +#include + +static void* +expat_g_malloc (size_t sz) +{ + return g_malloc (sz); +} + +static void* +expat_g_realloc (void *mem, size_t sz) +{ + return g_realloc (mem, sz); +} + +static XML_Memory_Handling_Suite memsuite = +{ + expat_g_malloc, + expat_g_realloc, + g_free +}; + +typedef struct +{ + Parser *parser; + const char *filename; + GString *content; + GError **error; + gboolean failed; +} ExpatParseContext; + +static dbus_bool_t +process_content (ExpatParseContext *context) +{ + if (context->failed) + return FALSE; + + if (context->content->len > 0) + { + if (!parser_content (context->parser, + context->content->str, + context->content->len, + context->error)) + { + context->failed = TRUE; + return FALSE; + } + g_string_set_size (context->content, 0); + } + + return TRUE; +} + +static void +expat_StartElementHandler (void *userData, + const XML_Char *name, + const XML_Char **atts) +{ + ExpatParseContext *context = userData; + int i; + char **names; + char **values; + + /* Expat seems to suck and can't abort the parse if we + * throw an error. Expat 2.0 is supposed to fix this. + */ + if (context->failed) + return; + + if (!process_content (context)) + return; + + /* "atts" is key, value, key, value, NULL */ + for (i = 0; atts[i] != NULL; ++i) + ; /* nothing */ + + g_assert (i % 2 == 0); + names = g_new0 (char *, i / 2 + 1); + values = g_new0 (char *, i / 2 + 1); + + i = 0; + while (atts[i] != NULL) + { + g_assert (i % 2 == 0); + names [i / 2] = (char*) atts[i]; + values[i / 2] = (char*) atts[i+1]; + + i += 2; + } + + if (!parser_start_element (context->parser, + name, + (const char **) names, + (const char **) values, + context->error)) + { + g_free (names); + g_free (values); + context->failed = TRUE; + return; + } + + g_free (names); + g_free (values); +} + +static void +expat_EndElementHandler (void *userData, + const XML_Char *name) +{ + ExpatParseContext *context = userData; + + if (!process_content (context)) + return; + + if (!parser_end_element (context->parser, + name, + context->error)) + { + context->failed = TRUE; + return; + } +} + +/* s is not 0 terminated. */ +static void +expat_CharacterDataHandler (void *userData, + const XML_Char *s, + int len) +{ + ExpatParseContext *context = userData; + + if (context->failed) + return; + + g_string_append_len (context->content, + s, len); +} + +Parser* +description_load_from_file (const char *filename, + GError **error) +{ + char *contents; + gsize len; + Parser *parser; + + contents = NULL; + if (!g_file_get_contents (filename, &contents, &len, error)) + return NULL; + + parser = description_load_from_string (contents, len, error); + g_free (contents); + + return parser; +} + +Parser* +description_load_from_string (const char *str, + int len, + GError **error) +{ + XML_Parser expat; + ExpatParseContext context; + + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + expat = NULL; + context.parser = NULL; + context.error = error; + context.failed = FALSE; + + expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL); + if (expat == NULL) + g_error ("No memory to create XML parser\n"); + + context.parser = parser_new (); + context.content = g_string_new (NULL); + + XML_SetUserData (expat, &context); + XML_SetElementHandler (expat, + expat_StartElementHandler, + expat_EndElementHandler); + XML_SetCharacterDataHandler (expat, + expat_CharacterDataHandler); + + if (!XML_Parse (expat, str, len, TRUE)) + { + if (context.error != NULL && + *context.error == NULL) + { + enum XML_Error e; + + e = XML_GetErrorCode (expat); + if (e == XML_ERROR_NO_MEMORY) + g_error ("Not enough memory to parse XML document"); + else + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + "Error in D-BUS description XML, line %d, column %d: %s\n", + XML_GetCurrentLineNumber (expat), + XML_GetCurrentColumnNumber (expat), + XML_ErrorString (e)); + } + + goto failed; + } + + if (context.failed) + goto failed; + + if (!parser_finished (context.parser, error)) + goto failed; + + XML_ParserFree (expat); + g_string_free (context.content, TRUE); + + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + return context.parser; + + failed: + g_return_val_if_fail (error == NULL || *error != NULL, NULL); + + g_string_free (context.content, TRUE); + if (expat) + XML_ParserFree (expat); + if (context.parser) + parser_unref (context.parser); + return NULL; +} diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c new file mode 100644 index 00000000..aa53265b --- /dev/null +++ b/glib/dbus-gobject.c @@ -0,0 +1,780 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gobject.c Exporting a GObject remotely + * + * 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-glib.h" +#include "dbus-gtest.h" +#include + +/** + * @addtogroup DBusGLibInternals + * @{ + */ + +static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT; +static GHashTable *info_hash = NULL; + +static char* +javacaps_to_uscore (const char *caps) +{ + const char *p; + GString *str; + + str = g_string_new (NULL); + p = caps; + while (*p) + { + if (g_ascii_isupper (*p)) + { + if (str->len > 0 && + (str->len < 2 || str->str[str->len-2] != '_')) + g_string_append_c (str, '_'); + g_string_append_c (str, g_ascii_tolower (*p)); + } + else + { + g_string_append_c (str, *p); + } + ++p; + } + + return g_string_free (str, FALSE); +} + +static char* +uscore_to_javacaps (const char *uscore) +{ + const char *p; + GString *str; + gboolean last_was_uscore; + + last_was_uscore = TRUE; + + str = g_string_new (NULL); + p = uscore; + while (*p) + { + if (*p == '-' || *p == '_') + { + last_was_uscore = TRUE; + } + else + { + if (last_was_uscore) + { + g_string_append_c (str, g_ascii_toupper (*p)); + last_was_uscore = FALSE; + } + else + g_string_append_c (str, *p); + } + ++p; + } + + return g_string_free (str, FALSE); +} + +static void +gobject_unregister_function (DBusConnection *connection, + void *user_data) +{ + GObject *object; + + object = G_OBJECT (user_data); + + +} + +static int +gtype_to_dbus_type (GType type) +{ + switch (type) + { + case G_TYPE_CHAR: + case G_TYPE_UCHAR: + return DBUS_TYPE_BYTE; + + case G_TYPE_BOOLEAN: + return DBUS_TYPE_BOOLEAN; + + /* long gets cut to 32 bits so the remote API is consistent + * on all architectures + */ + + case G_TYPE_LONG: + case G_TYPE_INT: + return DBUS_TYPE_INT32; + case G_TYPE_ULONG: + case G_TYPE_UINT: + return DBUS_TYPE_UINT32; + + case G_TYPE_INT64: + return DBUS_TYPE_INT64; + + case G_TYPE_UINT64: + return DBUS_TYPE_UINT64; + + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: + return DBUS_TYPE_DOUBLE; + + case G_TYPE_STRING: + return DBUS_TYPE_STRING; + + default: + return DBUS_TYPE_INVALID; + } +} + +static const char * +dbus_type_to_string (int type) +{ + switch (type) + { + case DBUS_TYPE_INVALID: + return "invalid"; + case DBUS_TYPE_NIL: + return "nil"; + case DBUS_TYPE_BOOLEAN: + return "boolean"; + case DBUS_TYPE_INT32: + return "int32"; + case DBUS_TYPE_UINT32: + return "uint32"; + case DBUS_TYPE_DOUBLE: + return "double"; + case DBUS_TYPE_STRING: + return "string"; + case DBUS_TYPE_NAMED: + return "named"; + case DBUS_TYPE_ARRAY: + return "array"; + case DBUS_TYPE_DICT: + return "dict"; + default: + return "unknown"; + } +} + +static DBusHandlerResult +handle_introspect (DBusConnection *connection, + DBusMessage *message, + GObject *object) +{ + GString *xml; + GParamSpec **specs; + unsigned int n_specs; + unsigned int i; + GType last_type; + DBusMessage *ret; + + xml = g_string_new (NULL); + + g_string_append (xml, "\n"); + + last_type = G_TYPE_INVALID; + + specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), + &n_specs); + + i = 0; + while (i < n_specs) + { + GParamSpec *spec = specs[i]; + gboolean can_set; + gboolean can_get; + char *s; + int dbus_type; + + dbus_type = gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec)); + if (dbus_type == DBUS_TYPE_INVALID) + goto next; + + if (spec->owner_type != last_type) + { + if (last_type != G_TYPE_INVALID) + g_string_append (xml, " \n"); + + + /* FIXME what should the namespace on the interface be in + * general? should people be able to set it for their + * objects? + */ + + g_string_append (xml, " owner_type)); + g_string_append (xml, "\">\n"); + + last_type = spec->owner_type; + } + + can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 && + (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); + + can_get = (spec->flags & G_PARAM_READABLE) != 0; + + s = uscore_to_javacaps (spec->name); + + if (can_set) + { + g_string_append (xml, " \n"); + + g_string_append (xml, " \n"); + } + + if (can_get) + { + g_string_append (xml, " \n"); + + g_string_append (xml, " \n"); + } + + g_free (s); + + next: + ++i; + } + + if (last_type != G_TYPE_INVALID) + g_string_append (xml, " \n"); + + g_free (specs); + + /* Close the XML, and send it to the requesting app */ + + g_string_append (xml, "\n"); + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + g_error ("out of memory"); + + dbus_message_append_args (message, + DBUS_TYPE_STRING, xml->str, + DBUS_TYPE_INVALID); + + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); + + g_string_free (xml, TRUE); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusMessage* +set_object_property (DBusConnection *connection, + DBusMessage *message, + GObject *object, + GParamSpec *pspec) +{ + GValue value; + DBusMessageIter iter; + int type; + gboolean can_set; + DBusMessage *ret; + + dbus_message_iter_init (message, &iter); + type = dbus_message_get_type (message); + + can_set = TRUE; + switch (type) + { + case DBUS_TYPE_BYTE: + { + unsigned char b; + + b = dbus_message_iter_get_byte (&iter); + + g_value_init (&value, G_TYPE_UCHAR); + + g_value_set_uchar (&value, b); + } + break; + case DBUS_TYPE_BOOLEAN: + { + gboolean b; + + b = dbus_message_iter_get_boolean (&iter); + + g_value_init (&value, G_TYPE_BOOLEAN); + + g_value_set_boolean (&value, b); + } + break; + case DBUS_TYPE_INT32: + { + gint32 i; + + i = dbus_message_iter_get_int32 (&iter); + + g_value_init (&value, G_TYPE_INT); + + g_value_set_int (&value, i); + } + break; + case DBUS_TYPE_UINT32: + { + guint32 i; + + i = dbus_message_iter_get_uint32 (&iter); + + g_value_init (&value, G_TYPE_UINT); + + g_value_set_uint (&value, i); + } + break; + case DBUS_TYPE_INT64: + { + gint64 i; + + i = dbus_message_iter_get_int64 (&iter); + + g_value_init (&value, G_TYPE_INT64); + + g_value_set_int64 (&value, i); + } + break; + case DBUS_TYPE_UINT64: + { + guint64 i; + + i = dbus_message_iter_get_uint64 (&iter); + + g_value_init (&value, G_TYPE_UINT64); + + g_value_set_uint64 (&value, i); + } + break; + case DBUS_TYPE_DOUBLE: + { + double d; + + d = dbus_message_iter_get_double (&iter); + + g_value_init (&value, G_TYPE_DOUBLE); + + g_value_set_double (&value, d); + } + break; + case DBUS_TYPE_STRING: + { + char *s; + + /* FIXME use a const string accessor */ + + s = dbus_message_iter_get_string (&iter); + + g_value_init (&value, G_TYPE_STRING); + + g_value_set_string (&value, s); + + g_free (s); + } + break; + + /* FIXME array and other types, especially byte array + * converted to G_TYPE_STRING + */ + + default: + can_set = FALSE; + break; + } + + /* The g_object_set_property() will transform some types, e.g. it + * will let you use a uchar to set an int property etc. Note that + * any error in value range or value conversion will just + * g_warning(). These GObject skels are not for secure applications. + */ + + if (can_set) + { + g_object_set_property (object, + pspec->name, + &value); + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + g_error ("out of memory"); + + g_value_unset (&value); + } + else + { + ret = dbus_message_new_error (message, + DBUS_ERROR_INVALID_ARGS, + "Argument's D-BUS type can't be converted to a GType"); + if (ret == NULL) + g_error ("out of memory"); + } + + return ret; +} + +static DBusMessage* +get_object_property (DBusConnection *connection, + DBusMessage *message, + GObject *object, + GParamSpec *pspec) +{ + GType value_type; + gboolean can_get; + DBusMessage *ret; + GValue value; + DBusMessageIter iter; + + value_type = G_PARAM_SPEC_VALUE_TYPE (pspec); + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + g_error ("out of memory"); + + can_get = TRUE; + g_value_init (&value, value_type); + g_object_get_property (object, pspec->name, &value); + + value_type = G_VALUE_TYPE (&value); + + dbus_message_append_iter_init (message, &iter); + + switch (value_type) + { + case G_TYPE_CHAR: + dbus_message_iter_append_byte (&iter, + g_value_get_char (&value)); + break; + case G_TYPE_UCHAR: + dbus_message_iter_append_byte (&iter, + g_value_get_uchar (&value)); + break; + case G_TYPE_BOOLEAN: + dbus_message_iter_append_boolean (&iter, + g_value_get_boolean (&value)); + break; + case G_TYPE_INT: + dbus_message_iter_append_int32 (&iter, + g_value_get_int (&value)); + break; + case G_TYPE_UINT: + dbus_message_iter_append_uint32 (&iter, + g_value_get_uint (&value)); + break; + /* long gets cut to 32 bits so the remote API is consistent + * on all architectures + */ + case G_TYPE_LONG: + dbus_message_iter_append_int32 (&iter, + g_value_get_long (&value)); + break; + case G_TYPE_ULONG: + dbus_message_iter_append_uint32 (&iter, + g_value_get_ulong (&value)); + break; + case G_TYPE_INT64: + dbus_message_iter_append_int64 (&iter, + g_value_get_int64 (&value)); + break; + case G_TYPE_UINT64: + dbus_message_iter_append_uint64 (&iter, + g_value_get_uint64 (&value)); + break; + case G_TYPE_FLOAT: + dbus_message_iter_append_double (&iter, + g_value_get_float (&value)); + break; + case G_TYPE_DOUBLE: + dbus_message_iter_append_double (&iter, + g_value_get_double (&value)); + break; + case G_TYPE_STRING: + /* FIXME, the GValue string may not be valid UTF-8 */ + dbus_message_iter_append_string (&iter, + g_value_get_string (&value)); + break; + default: + can_get = FALSE; + break; + } + + g_value_unset (&value); + + if (!can_get) + { + dbus_message_unref (ret); + ret = dbus_message_new_error (message, + DBUS_ERROR_UNKNOWN_METHOD, + "Can't convert GType of object property to a D-BUS type"); + } + + return ret; +} + +static DBusHandlerResult +gobject_message_function (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + const DBusGObjectInfo *info; + GParamSpec *pspec; + GObject *object; + const char *member; + gboolean setter; + gboolean getter; + char *s; + + object = G_OBJECT (user_data); + + if (dbus_message_is_method_call (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE, + "Introspect")) + return handle_introspect (connection, message, object); + + member = dbus_message_get_member (message); + + /* Try the metainfo, which lets us invoke methods */ + + g_static_mutex_lock (&info_hash_mutex); + /* FIXME this needs to walk up the inheritance tree, not + * just look at the most-derived class + */ + info = g_hash_table_lookup (info_hash, + G_OBJECT_GET_CLASS (object)); + g_static_mutex_unlock (&info_hash_mutex); + + if (info != NULL) + { + + + + } + + /* If no metainfo, we can still do properties and signals + * via standard GLib introspection + */ + setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't'); + getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't'); + + if (!(setter || getter)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + s = javacaps_to_uscore (&member[3]); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), + s); + + g_free (s); + + if (pspec != NULL) + { + DBusMessage *ret; + + if (setter) + { + ret = set_object_property (connection, message, + object, pspec); + } + else if (getter) + { + ret = get_object_property (connection, message, + object, pspec); + } + else + { + g_assert_not_reached (); + ret = NULL; + } + + g_assert (ret != NULL); + + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusObjectPathVTable gobject_dbus_vtable = { + gobject_unregister_function, + gobject_message_function, + NULL +}; + +/** @} */ /* end of internals */ + +/** + * @addtogroup DBusGLib + * @{ + */ + +/** + * Install introspection information about the given object class + * sufficient to allow methods on the object to be invoked by name. + * The introspection information is normally generated by + * dbus-glib-tool, then this function is called in the + * class_init() for the object class. + * + * Once introspection information has been installed, instances of the + * object registered with dbus_connection_register_gobject() can have + * their methods invoked remotely. + * + * @param object_class class struct of the object + * @param info introspection data generated by dbus-glib-tool + */ +void +dbus_gobject_class_install_info (GObjectClass *object_class, + const DBusGObjectInfo *info) +{ + g_return_if_fail (G_IS_OBJECT_CLASS (object_class)); + + g_static_mutex_lock (&info_hash_mutex); + + if (info_hash == NULL) + { + info_hash = g_hash_table_new (NULL, NULL); /* direct hash */ + } + + g_hash_table_replace (info_hash, object_class, (void*) info); + + g_static_mutex_unlock (&info_hash_mutex); +} + +static char** +split_path (const char *path) +{ + int len; + char **split; + int n_components; + int i, j, comp; + + len = strlen (path); + + n_components = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + n_components += 1; + ++i; + } + + split = g_new0 (char*, n_components + 1); + + comp = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + ++i; + j = i; + + while (j < len && path[j] != '/') + ++j; + + /* Now [i, j) is the path component */ + g_assert (i < j); + g_assert (path[i] != '/'); + g_assert (j == len || path[j] == '/'); + + split[comp] = g_strndup (&path[i], j - i + 1); + + split[comp][j-i] = '\0'; + + ++comp; + i = j; + } + g_assert (i == len); + + return split; +} + +/** + * Registers a GObject at the given path. Properties, methods, and signals + * of the object can then be accessed remotely. Methods are only available + * if method introspection data has been added to the object's class + * with g_object_class_install_info(). + * + * The registration will be cancelled if either the DBusConnection or + * the GObject gets finalized. + * + * @param connection the D-BUS connection + * @param at_path the path where the object will live (the object's name) + * @param object the object + */ +void +dbus_connection_register_gobject (DBusConnection *connection, + const char *at_path, + GObject *object) +{ + char **split; + + g_return_if_fail (connection != NULL); + g_return_if_fail (at_path != NULL); + g_return_if_fail (G_IS_OBJECT (object)); + + split = split_path (at_path); + + if (!dbus_connection_register_object_path (connection, + (const char**) split, + &gobject_dbus_vtable, + object)) + g_error ("Failed to register GObject with DBusConnection"); + + g_strfreev (split); + + /* FIXME set up memory management (so we break the + * registration if object or connection vanishes) + */ +} + +/** @} */ /* end of public API */ + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGLibInternals + * Unit test for GLib GObject integration ("skeletons") + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gobject_test (const char *test_data_dir) +{ + static struct { const char *javacaps; const char *uscore; } name_pairs[] = { + { "setFoo", "set_foo" }, + { "foo", "foo" }, + { "getFooBar", "get_foo_bar" }, + { "Hello", "hello" }, + { "frobateUIHandler", "frobate_ui_handler" } + }; + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c index 6fea4abc..c2b54d31 100644 --- a/glib/dbus-gparser.c +++ b/glib/dbus-gparser.c @@ -22,11 +22,152 @@ */ #include "dbus-gparser.h" #include "dbus-gidl.h" +#include + +#include +#define _(x) gettext ((x)) +#define N_(x) x + +#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0) + +typedef struct +{ + const char *name; + const char **retloc; +} LocateAttr; + +static gboolean +locate_attributes (const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error, + const char *first_attribute_name, + const char **first_attribute_retloc, + ...) +{ + va_list args; + const char *name; + const char **retloc; + int n_attrs; +#define MAX_ATTRS 24 + LocateAttr attrs[MAX_ATTRS]; + gboolean retval; + int i; + + g_return_val_if_fail (first_attribute_name != NULL, FALSE); + g_return_val_if_fail (first_attribute_retloc != NULL, FALSE); + + retval = TRUE; + + n_attrs = 1; + attrs[0].name = first_attribute_name; + attrs[0].retloc = first_attribute_retloc; + *first_attribute_retloc = NULL; + + va_start (args, first_attribute_retloc); + + name = va_arg (args, const char*); + retloc = va_arg (args, const char**); + + while (name != NULL) + { + g_return_val_if_fail (retloc != NULL, FALSE); + + g_assert (n_attrs < MAX_ATTRS); + + attrs[n_attrs].name = name; + attrs[n_attrs].retloc = retloc; + n_attrs += 1; + *retloc = NULL; + + name = va_arg (args, const char*); + retloc = va_arg (args, const char**); + } + + va_end (args); + + if (!retval) + return retval; + + i = 0; + while (attribute_names[i]) + { + int j; + gboolean found; + + found = FALSE; + j = 0; + while (j < n_attrs) + { + if (strcmp (attrs[j].name, attribute_names[i]) == 0) + { + retloc = attrs[j].retloc; + + if (*retloc != NULL) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Attribute \"%s\" repeated twice on the same <%s> element"), + attrs[j].name, element_name); + retval = FALSE; + goto out; + } + + *retloc = attribute_values[i]; + found = TRUE; + } + + ++j; + } + + if (!found) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Attribute \"%s\" is invalid on <%s> element in this context"), + attribute_names[i], element_name); + retval = FALSE; + goto out; + } + + ++i; + } + + out: + return retval; +} + +static gboolean +check_no_attributes (const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + if (attribute_names[0] != NULL) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Attribute \"%s\" is invalid on <%s> element in this context"), + attribute_names[0], element_name); + return FALSE; + } + + return TRUE; +} struct Parser { int refcount; + NodeInfo *result; /* Filled in when we pop the last node */ + GSList *node_stack; + InterfaceInfo *interface; + MethodInfo *method; + SignalInfo *signal; + ArgInfo *arg; }; Parser* @@ -53,7 +194,8 @@ parser_unref (Parser *parser) parser->refcount -= 1; if (parser->refcount == 0) { - + if (parser->result) + node_info_unref (parser->result); g_free (parser); } @@ -64,11 +206,12 @@ parser_check_doctype (Parser *parser, const char *doctype, GError **error) { - g_return_val_if_fail (error == NULL || *error == NULL); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (strcmp (doctype, "dbus_description") != 0) { g_set_error (error, + G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "D-BUS description file has the wrong document type %s, use dbus_description", doctype); @@ -78,6 +221,324 @@ parser_check_doctype (Parser *parser, return TRUE; } +static gboolean +parse_node (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + const char *name; + NodeInfo *node; + + if (parser->interface || + parser->method || + parser->signal || + parser->arg) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Can't put a <%s> element here"), + element_name); + return FALSE; + } + + name = NULL; + if (!locate_attributes (element_name, attribute_names, + attribute_values, error, + "name", &name, + NULL)) + return FALSE; + + /* Only the root node can have no name */ + if (parser->node_stack != NULL && name == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute required on <%s> element "), + "name", element_name); + return FALSE; + } + + node = node_info_new (name); + parser->node_stack = g_slist_prepend (parser->node_stack, + node); + + return TRUE; +} + +static gboolean +parse_interface (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + const char *name; + InterfaceInfo *iface; + NodeInfo *top; + + if (parser->interface || + parser->method || + parser->signal || + parser->arg || + (parser->node_stack == NULL)) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Can't put a <%s> element here"), + element_name); + return FALSE; + } + + name = NULL; + if (!locate_attributes (element_name, attribute_names, + attribute_values, error, + "name", &name, + NULL)) + return FALSE; + + if (name == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute required on <%s> element "), + "name", element_name); + return FALSE; + } + + top = parser->node_stack->data; + + iface = interface_info_new (name); + node_info_add_interface (top, iface); + interface_info_unref (iface); + + parser->interface = iface; + + return TRUE; +} + +static gboolean +parse_method (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + const char *name; + MethodInfo *method; + NodeInfo *top; + + if (parser->interface == NULL || + parser->node_stack == NULL || + parser->method || + parser->signal || + parser->arg) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Can't put a <%s> element here"), + element_name); + return FALSE; + } + + name = NULL; + if (!locate_attributes (element_name, attribute_names, + attribute_values, error, + "name", &name, + NULL)) + return FALSE; + + if (name == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute required on <%s> element "), + "name", element_name); + return FALSE; + } + + top = parser->node_stack->data; + + method = method_info_new (name); + interface_info_add_method (parser->interface, method); + method_info_unref (method); + + parser->method = method; + + return TRUE; +} + +static gboolean +parse_signal (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + const char *name; + SignalInfo *signal; + NodeInfo *top; + + if (parser->interface == NULL || + parser->node_stack == NULL || + parser->signal || + parser->signal || + parser->arg) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Can't put a <%s> element here"), + element_name); + return FALSE; + } + + name = NULL; + if (!locate_attributes (element_name, attribute_names, + attribute_values, error, + "name", &name, + NULL)) + return FALSE; + + if (name == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute required on <%s> element "), + "name", element_name); + return FALSE; + } + + top = parser->node_stack->data; + + signal = signal_info_new (name); + interface_info_add_signal (parser->interface, signal); + signal_info_unref (signal); + + parser->signal = signal; + + return TRUE; +} + +static int +basic_type_from_string (const char *str) +{ + if (strcmp (str, "string") == 0) + return DBUS_TYPE_STRING; + else if (strcmp (str, "int32") == 0) + return DBUS_TYPE_INT32; + else if (strcmp (str, "uint32") == 0) + return DBUS_TYPE_UINT32; + else if (strcmp (str, "int64") == 0) + return DBUS_TYPE_INT64; + else if (strcmp (str, "uint64") == 0) + return DBUS_TYPE_UINT64; + else if (strcmp (str, "double") == 0) + return DBUS_TYPE_DOUBLE; + else if (strcmp (str, "byte") == 0) + return DBUS_TYPE_BYTE; + else if (strcmp (str, "boolean") == 0) + return DBUS_TYPE_BOOLEAN; + else if (strcmp (str, "byte") == 0) + return DBUS_TYPE_BYTE; + else if (strcmp (str, "object") == 0) + return DBUS_TYPE_OBJECT_PATH; + else + return DBUS_TYPE_INVALID; +} + +static int +type_from_string (const char *str) +{ + return basic_type_from_string (str); +} + +static gboolean +parse_arg (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + const char *name; + const char *type; + const char *direction; + ArgDirection dir; + int t; + ArgInfo *arg; + + if (!(parser->method || parser->signal) || + parser->node_stack == NULL || + parser->arg) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Can't put a <%s> element here"), + element_name); + return FALSE; + } + + name = NULL; + if (!locate_attributes (element_name, attribute_names, + attribute_values, error, + "name", &name, + "type", &type, + "direction", &direction, + NULL)) + return FALSE; + + /* name can be null for args */ + + if (type == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute required on <%s> element "), + "type", element_name); + return FALSE; + } + + if (direction == NULL) + { + /* methods default to in, signal to out */ + if (parser->method) + direction = "in"; + else if (parser->signal) + direction = "out"; + else + g_assert_not_reached (); + } + + if (strcmp (direction, "in") == 0) + dir = ARG_IN; + else if (strcmp (direction, "out") == 0) + dir = ARG_OUT; + else + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute on <%s> has value \"in\" or \"out\""), + "direction", element_name); + return FALSE; + } + + t = type_from_string (type); + + arg = arg_info_new (name, dir, t); + if (parser->method) + method_info_add_arg (parser->method, arg); + else if (parser->signal) + signal_info_add_arg (parser->signal, arg); + else + g_assert_not_reached (); + + arg_info_unref (arg); + + parser->arg = arg; + + return TRUE; +} + gboolean parser_start_element (Parser *parser, const char *element_name, @@ -85,8 +546,46 @@ parser_start_element (Parser *parser, const char **attribute_values, GError **error) { - g_return_val_if_fail (error == NULL || *error == NULL); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + if (ELEMENT_IS ("node")) + { + if (!parse_node (parser, element_name, attribute_names, + attribute_values, error)) + return FALSE; + } + else if (ELEMENT_IS ("interface")) + { + if (!parse_interface (parser, element_name, attribute_names, + attribute_values, error)) + return FALSE; + } + else if (ELEMENT_IS ("method")) + { + if (!parse_method (parser, element_name, attribute_names, + attribute_values, error)) + return FALSE; + } + else if (ELEMENT_IS ("signal")) + { + if (!parse_signal (parser, element_name, attribute_names, + attribute_values, error)) + return FALSE; + } + else if (ELEMENT_IS ("arg")) + { + if (!parse_arg (parser, element_name, attribute_names, + attribute_values, error)) + return FALSE; + } + else + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Element <%s> not recognized"), + element_name); + } + return TRUE; } @@ -95,8 +594,40 @@ parser_end_element (Parser *parser, const char *element_name, GError **error) { - g_return_val_if_fail (error == NULL || *error == NULL); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (ELEMENT_IS ("interface")) + { + parser->interface = NULL; + } + else if (ELEMENT_IS ("method")) + { + parser->method = NULL; + } + else if (ELEMENT_IS ("signal")) + { + parser->signal = NULL; + } + else if (ELEMENT_IS ("arg")) + { + parser->arg = NULL; + } + else if (ELEMENT_IS ("node")) + { + NodeInfo *top; + g_assert (parser->node_stack != NULL); + top = parser->node_stack->data; + + parser->node_stack = g_slist_remove (parser->node_stack, + top); + + if (parser->node_stack == NULL) + parser->result = top; /* We are done, store the result */ + } + else + g_assert_not_reached (); /* should have had an error on start_element */ + return TRUE; } @@ -106,7 +637,7 @@ parser_content (Parser *parser, int len, GError **error) { - g_return_val_if_fail (error == NULL || *error == NULL); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); return TRUE; } @@ -115,7 +646,13 @@ gboolean parser_finished (Parser *parser, GError **error) { - g_return_val_if_fail (error == NULL || *error == NULL); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); return TRUE; } + +NodeInfo* +parser_get_nodes (Parser *parser) +{ + return parser->result; +} diff --git a/glib/dbus-gparser.h b/glib/dbus-gparser.h index 01339fbf..3e87165b 100644 --- a/glib/dbus-gparser.h +++ b/glib/dbus-gparser.h @@ -25,10 +25,10 @@ #include #include +#include "dbus-gidl.h" G_BEGIN_DECLS - typedef struct Parser Parser; Parser* parser_new (void); @@ -52,7 +52,13 @@ gboolean parser_content (Parser *parser, gboolean parser_finished (Parser *parser, GError **error); +Parser* description_load_from_file (const char *filename, + GError **error); +Parser* description_load_from_string (const char *str, + int len, + GError **error); +NodeInfo* parser_get_nodes (Parser *parser); G_END_DECLS -- cgit v1.2.1 From 0453b2be603d4a8fcd12be3097b7eadc25838018 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 3 Sep 2003 23:27:36 +0000 Subject: forgot to cvs add dbus-gtest.[hc] --- glib/dbus-gtest.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ glib/dbus-gtest.h | 34 ++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 glib/dbus-gtest.c create mode 100644 glib/dbus-gtest.h diff --git a/glib/dbus-gtest.c b/glib/dbus-gtest.c new file mode 100644 index 00000000..b853d3ed --- /dev/null +++ b/glib/dbus-gtest.c @@ -0,0 +1,73 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-test.c Program to run all tests + * + * 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 +#include "dbus-gtest.h" +#include +#include + +#ifdef DBUS_BUILD_TESTS +static void +die (const char *failure) +{ + fprintf (stderr, "Unit test failed: %s\n", failure); + exit (1); +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * An exported symbol to be run in order to execute + * unit tests. Should not be used by + * any app other than our test app, this symbol + * won't exist in some builds of the library. + * (with --enable-tests=no) + * + * @param test_data_dir the directory with test data (test/data normally) + */ +void +dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir) +{ +#ifdef DBUS_BUILD_TESTS + if (test_data_dir == NULL) + test_data_dir = g_getenv ("DBUS_TEST_DATA"); + + if (test_data_dir != NULL) + printf ("Test data in %s\n", test_data_dir); + else + printf ("No test data!\n"); + + printf ("%s: running mainloop integration tests\n", "dbus-glib-test"); + if (!_dbus_gmain_test (test_data_dir)) + die ("gmain"); + + printf ("%s: running GObject tests\n", "dbus-glib-test"); + if (!_dbus_gobject_test (test_data_dir)) + die ("gobject"); + + printf ("%s: completed successfully\n", "dbus-glib-test"); +#else + printf ("Not compiled with unit tests, not running any\n"); +#endif +} + + diff --git a/glib/dbus-gtest.h b/glib/dbus-gtest.h new file mode 100644 index 00000000..6a33bdae --- /dev/null +++ b/glib/dbus-gtest.h @@ -0,0 +1,34 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gtest.h Declarations of test functions. + * + * 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_GLIB_TEST_H +#define DBUS_GLIB_TEST_H + +#include "dbus-glib.h" + +dbus_bool_t _dbus_gmain_test (const char *test_data_dir); +dbus_bool_t _dbus_gobject_test (const char *test_data_dir); + +void dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir); + +#endif /* DBUS_GLIB_TEST_H */ -- cgit v1.2.1 From 636be6f92d4d8effd392ad1f894738849ec7af76 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 4 Sep 2003 00:21:36 +0000 Subject: 2003-09-03 Havoc Pennington * test/glib/Makefile.am: add this with random glib-linked test programs * glib/Makefile.am: remove the random test programs from here, leave only the unit tests * glib/dbus-gobject.c (_dbus_gobject_test): add test for uscore/javacaps conversion, and fix (get_object_property, set_object_property): change to .NET convention for mapping props to methods, set_FooBar/get_FooBar, since one language has such a convention we may as well copy it. Plus real methods in either getFooBar or get_foo_bar style won't collide with this convention. --- ChangeLog | 16 +++ configure.in | 1 + glib/Makefile.am | 34 +------ glib/dbus-gobject.c | 63 +++++++++--- glib/test-dbus-glib.c | 52 ---------- glib/test-profile.c | 226 ----------------------------------------- glib/test-thread-client.c | 98 ------------------ glib/test-thread-server.c | 209 ------------------------------------- glib/test-thread.h | 1 - test/Makefile.am | 7 ++ test/glib/Makefile.am | 44 ++++++++ test/glib/test-dbus-glib.c | 52 ++++++++++ test/glib/test-profile.c | 226 +++++++++++++++++++++++++++++++++++++++++ test/glib/test-thread-client.c | 98 ++++++++++++++++++ test/glib/test-thread-server.c | 209 +++++++++++++++++++++++++++++++++++++ test/glib/test-thread.h | 1 + 16 files changed, 704 insertions(+), 633 deletions(-) delete mode 100644 glib/test-dbus-glib.c delete mode 100644 glib/test-profile.c delete mode 100644 glib/test-thread-client.c delete mode 100644 glib/test-thread-server.c delete mode 100644 glib/test-thread.h create mode 100644 test/glib/Makefile.am create mode 100644 test/glib/test-dbus-glib.c create mode 100644 test/glib/test-profile.c create mode 100644 test/glib/test-thread-client.c create mode 100644 test/glib/test-thread-server.c create mode 100644 test/glib/test-thread.h diff --git a/ChangeLog b/ChangeLog index d9557bed..ccca8a8e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2003-09-03 Havoc Pennington + + * test/glib/Makefile.am: add this with random glib-linked test + programs + + * glib/Makefile.am: remove the random test programs from here, + leave only the unit tests + + * glib/dbus-gobject.c (_dbus_gobject_test): add test for + uscore/javacaps conversion, and fix + (get_object_property, set_object_property): change to .NET + convention for mapping props to methods, set_FooBar/get_FooBar, + since one language has such a convention we may as well copy it. + Plus real methods in either getFooBar or get_foo_bar style won't + collide with this convention. + 2003-09-01 Havoc Pennington * glib/dbus-gparser.c: implement diff --git a/configure.in b/configure.in index 1125ef60..c403fd8c 100644 --- a/configure.in +++ b/configure.in @@ -826,6 +826,7 @@ mono/Makefile bus/Makefile tools/Makefile test/Makefile +test/glib/Makefile doc/Makefile dbus-1.pc dbus-glib-1.pc diff --git a/glib/Makefile.am b/glib/Makefile.am index f3b43ed3..65d71cfd 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -34,30 +34,9 @@ dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-glib-1.la $(top_builddir)/d if DBUS_BUILD_TESTS -if HAVE_GLIB_THREADS -THREAD_APPS=test-thread-server test-thread-client test-profile - -test_thread_server_SOURCES= \ - test-thread-server.c \ - test-thread.h - -test_thread_server_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la - -test_thread_client_SOURCES= \ - test-thread-client.c \ - test-thread.h - -test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la -endif - ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we ## build even when not doing "make check" -noinst_PROGRAMS= $(TESTS) test-dbus-glib $(THREAD_APPS) - -test_dbus_glib_SOURCES= \ - test-dbus-glib.c - -test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la +noinst_PROGRAMS= $(TESTS) ## note that TESTS has special meaning (stuff to use in make check) ## so if adding tests not to be run in make check, don't add them to @@ -74,15 +53,4 @@ else ### not building tests TESTS= -if HAVE_GLIB_THREADS -noinst_PROGRAMS=test-profile -endif - endif - -if HAVE_GLIB_THREADS -test_profile_SOURCES= \ - test-profile.c - -test_profile_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la -endif \ No newline at end of file diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index aa53265b..b0f6c139 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -35,7 +35,7 @@ static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT; static GHashTable *info_hash = NULL; static char* -javacaps_to_uscore (const char *caps) +wincaps_to_uscore (const char *caps) { const char *p; GString *str; @@ -62,7 +62,7 @@ javacaps_to_uscore (const char *caps) } static char* -uscore_to_javacaps (const char *uscore) +uscore_to_wincaps (const char *uscore) { const char *p; GString *str; @@ -233,11 +233,11 @@ handle_introspect (DBusConnection *connection, can_get = (spec->flags & G_PARAM_READABLE) != 0; - s = uscore_to_javacaps (spec->name); + s = uscore_to_wincaps (spec->name); if (can_set) { - g_string_append (xml, " \n"); @@ -248,7 +248,7 @@ handle_introspect (DBusConnection *connection, if (can_get) { - g_string_append (xml, " \n"); @@ -578,13 +578,13 @@ gobject_message_function (DBusConnection *connection, /* If no metainfo, we can still do properties and signals * via standard GLib introspection */ - setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't'); - getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't'); + setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't' && member[3] == '_'); + getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't' && member[3] == '_'); if (!(setter || getter)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - s = javacaps_to_uscore (&member[3]); + s = wincaps_to_uscore (&member[4]); pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), s); @@ -757,6 +757,7 @@ dbus_connection_register_gobject (DBusConnection *connection, /** @} */ /* end of public API */ #ifdef DBUS_BUILD_TESTS +#include /** * @ingroup DBusGLibInternals @@ -766,14 +767,48 @@ dbus_connection_register_gobject (DBusConnection *connection, dbus_bool_t _dbus_gobject_test (const char *test_data_dir) { - static struct { const char *javacaps; const char *uscore; } name_pairs[] = { - { "setFoo", "set_foo" }, - { "foo", "foo" }, - { "getFooBar", "get_foo_bar" }, - { "Hello", "hello" }, - { "frobateUIHandler", "frobate_ui_handler" } + int i; + static struct { const char *wincaps; const char *uscore; } name_pairs[] = { + { "SetFoo", "set_foo" }, + { "Foo", "foo" }, + { "GetFooBar", "get_foo_bar" }, + { "Hello", "hello" } + + /* Impossible-to-handle cases */ + /* { "FrobateUIHandler", "frobate_ui_handler" } */ }; + i = 0; + while (i < (int) G_N_ELEMENTS (name_pairs)) + { + char *uscore; + char *wincaps; + + uscore = wincaps_to_uscore (name_pairs[i].wincaps); + wincaps = uscore_to_wincaps (name_pairs[i].uscore); + + if (strcmp (uscore, name_pairs[i].uscore) != 0) + { + g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n", + name_pairs[i].wincaps, name_pairs[i].uscore, + uscore); + exit (1); + } + + if (strcmp (wincaps, name_pairs[i].wincaps) != 0) + { + g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n", + name_pairs[i].uscore, name_pairs[i].wincaps, + wincaps); + exit (1); + } + + g_free (uscore); + g_free (wincaps); + + ++i; + } + return TRUE; } diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c deleted file mode 100644 index beda0a7a..00000000 --- a/glib/test-dbus-glib.c +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -#include "dbus-glib.h" -#include - -int -main (int argc, char **argv) -{ - DBusConnection *connection; - DBusMessage *message, *reply; - GMainLoop *loop; - DBusError error; - - if (argc < 2) - { - g_printerr ("Give the server address as an argument\n"); - return 1; - } - - loop = g_main_loop_new (NULL, FALSE); - - dbus_error_init (&error); - connection = dbus_connection_open (argv[1], &error); - if (connection == NULL) - { - g_printerr ("Failed to open connection to %s: %s\n", argv[1], - error.message); - dbus_error_free (&error); - return 1; - } - - dbus_connection_setup_with_g_main (connection, NULL); - - message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, - DBUS_PATH_ORG_FREEDESKTOP_DBUS, - DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, - "Hello"); - - dbus_error_init (&error); - reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); - if (reply == NULL) - { - g_printerr ("Error on hello message: %s\n", error.message); - dbus_error_free (&error); - return 1; - } - - g_print ("reply received\n"); - - g_main_loop_run (loop); - - return 0; -} diff --git a/glib/test-profile.c b/glib/test-profile.c deleted file mode 100644 index 6d9d8e7f..00000000 --- a/glib/test-profile.c +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* test-profile.c Program that does basic message-response for timing - * - * 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 - * - */ - -/* FIXME this test is wacky since both client and server keep - * sending each other method calls, but nobody sends - * a DBUS_MESSAGE_TYPE_METHOD_RETURN - */ - -#include -#include -#include "dbus-glib.h" -#include - -#define N_CLIENT_THREADS 1 -#define N_ITERATIONS 1000 -#define PAYLOAD_SIZE 30 -#define ECHO_PATH "/org/freedesktop/EchoTest" -#define ECHO_INTERFACE "org.freedesktop.EchoTest" -#define ECHO_METHOD "EchoProfile" - -static const char *address; -static unsigned char *payload; - -static void -send_echo_message (DBusConnection *connection) -{ - DBusMessage *message; - - message = dbus_message_new_method_call (NULL, ECHO_PATH, - ECHO_INTERFACE, ECHO_METHOD); - dbus_message_append_args (message, - DBUS_TYPE_STRING, "Hello World!", - DBUS_TYPE_INT32, 123456, -#if 1 - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - payload, PAYLOAD_SIZE, -#endif - DBUS_TYPE_INVALID); - - dbus_connection_send (connection, message, NULL); - dbus_message_unref (message); - dbus_connection_flush (connection); -} - -static DBusHandlerResult -client_filter (DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - int *iterations = user_data; - - if (dbus_message_is_signal (message, - DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, - "Disconnected")) - { - g_printerr ("Client thread disconnected\n"); - exit (1); - } - else if (dbus_message_is_method_call (message, - ECHO_INTERFACE, ECHO_METHOD)) - { - *iterations += 1; - if (*iterations >= N_ITERATIONS) - { - g_print ("Completed %d iterations\n", N_ITERATIONS); - exit (0); - } - send_echo_message (connection); - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static void* -thread_func (void *data) -{ - DBusError error; - GMainContext *context; - GMainLoop *loop; - DBusConnection *connection; - int iterations; - - g_printerr ("Starting client thread\n"); - - dbus_error_init (&error); - connection = dbus_connection_open (address, &error); - if (connection == NULL) - { - g_printerr ("could not open connection: %s\n", error.message); - dbus_error_free (&error); - exit (1); - } - - iterations = 1; - - if (!dbus_connection_add_filter (connection, - client_filter, &iterations, NULL)) - g_error ("no memory"); - - context = g_main_context_new (); - loop = g_main_loop_new (context, FALSE); - - dbus_connection_setup_with_g_main (connection, context); - - g_printerr ("Client thread sending message to prime pingpong\n"); - send_echo_message (connection); - g_printerr ("Client thread sent message\n"); - - g_printerr ("Client thread entering main loop\n"); - g_main_loop_run (loop); - g_printerr ("Client thread exiting main loop\n"); - - g_main_loop_unref (loop); - g_main_context_unref (context); - - return NULL; -} - -static DBusHandlerResult -server_filter (DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - if (dbus_message_is_signal (message, - DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, - "Disconnected")) - { - g_printerr ("Server thread disconnected\n"); - exit (1); - } - else if (dbus_message_is_method_call (message, - ECHO_INTERFACE, - ECHO_METHOD)) - { - send_echo_message (connection); - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static void -new_connection_callback (DBusServer *server, - DBusConnection *new_connection, - void *user_data) -{ - dbus_connection_ref (new_connection); - dbus_connection_setup_with_g_main (new_connection, NULL); - - if (!dbus_connection_add_filter (new_connection, - server_filter, NULL, NULL)) - g_error ("no memory"); - - - /* FIXME we leak the handler */ -} - -int -main (int argc, char *argv[]) -{ - GMainLoop *loop; - DBusError error; - DBusServer *server; - int i; - - g_thread_init (NULL); - dbus_gthread_init (); - - dbus_error_init (&error); - server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, - &error); - if (server == NULL) - { - g_printerr ("Could not start server: %s\n", - error.message); - return 1; - } - - address = dbus_server_get_address (server); - payload = g_malloc (PAYLOAD_SIZE); - - dbus_server_set_new_connection_function (server, - new_connection_callback, - NULL, NULL); - - loop = g_main_loop_new (NULL, FALSE); - - dbus_server_setup_with_g_main (server, NULL); - - for (i = 0; i < N_CLIENT_THREADS; i++) - { - g_thread_create (thread_func, NULL, FALSE, NULL); - } - - g_printerr ("Server thread entering main loop\n"); - g_main_loop_run (loop); - g_printerr ("Server thread exiting main loop\n"); - - dbus_server_unref (server); - - g_main_loop_unref (loop); - - return 0; -} - diff --git a/glib/test-thread-client.c b/glib/test-thread-client.c deleted file mode 100644 index d51d4e6a..00000000 --- a/glib/test-thread-client.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include "dbus-glib.h" -#include -#include -#include - -#include "test-thread.h" - -DBusConnection *connection; - -static gpointer -thread_func (gpointer data) -{ - gint32 threadnr = GPOINTER_TO_INT (data); - guint32 counter = 0; - DBusMessageIter iter; - DBusMessage *message; - char *str; - - while (1) - { - message = dbus_message_new_method_call (NULL, - "/org/freedesktop/ThreadTest", - "org.freedesktop.ThreadTest", - "TestMethod"); - - dbus_message_append_iter_init (message, &iter); - - if (!dbus_message_iter_append_int32 (&iter, threadnr)) - { - g_print ("thread %d: append threadnr failed\n", threadnr); - } - - if (!dbus_message_iter_append_uint32 (&iter, counter)) - { - g_print ("thread %d: append counter (%d) failed\n", threadnr, counter); - } - - str = g_strdup_printf ("Thread %d-%d\n", threadnr, counter); - if (!dbus_message_iter_append_string (&iter, str)) - { - g_print ("thread %d: append string (%s) failed\n", threadnr, str); - } - g_free (str); - - if (!dbus_connection_send (connection, - message, - NULL)) - { - g_print ("thread %d: send message failed\n", threadnr); - } - - dbus_message_unref (message); - - counter ++; - } - - return NULL; -} - -int -main (int argc, char *argv[]) -{ - GMainLoop *loop; - DBusError error; - int i; - - g_thread_init (NULL); - dbus_gthread_init (); - - if(argc < 2) - { - g_error("Need an address as argv[1]\n"); - return 1; - } - - dbus_error_init (&error); - connection = dbus_connection_open (argv[1], &error); - if (connection == NULL) - { - g_printerr ("could not open connection: %s\n", error.message); - dbus_error_free (&error); - return 1; - } - - dbus_connection_setup_with_g_main (connection, NULL); - - for (i = 0; i < N_TEST_THREADS; i++) - { - g_thread_create (thread_func, GINT_TO_POINTER (i), FALSE, NULL); - } - - loop = g_main_loop_new (NULL, FALSE); - g_main_run (loop); - - return 0; -} - diff --git a/glib/test-thread-server.c b/glib/test-thread-server.c deleted file mode 100644 index 8898ca7f..00000000 --- a/glib/test-thread-server.c +++ /dev/null @@ -1,209 +0,0 @@ -#include -#include "dbus-glib.h" -#include -#include - -#include "test-thread.h" - -typedef struct { - guint32 counters[N_TEST_THREADS]; -} ThreadTestData; - -static ThreadTestData * -thread_test_data_new (void) -{ - ThreadTestData *data; - - data = g_new0 (ThreadTestData, 1); - - return data; -} - -static void -thread_test_data_free (ThreadTestData *data) -{ - g_free (data); -} - -static DBusHandlerResult -filter_test_message (DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - ThreadTestData *data = user_data; - DBusMessageIter iter; - gint32 threadnr; - guint32 counter; - char *str, *expected_str; - GString *counter_str; - int i; - - if (!dbus_message_is_method_call (message, "org.freedesktop.ThreadTest", - "TestMethod")) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - dbus_message_iter_init (message, &iter); - - if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32) - { - g_print ("First arg not right type\n"); - goto out; - } - threadnr = dbus_message_iter_get_int32 (&iter); - if (threadnr < 0 || threadnr >= N_TEST_THREADS) - { - g_print ("Invalid thread nr\n"); - goto out; - } - - if (! dbus_message_iter_next (&iter)) - { - g_print ("Couldn't get second arg\n"); - goto out; - } - - if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32) - { - g_print ("Second arg not right type\n"); - goto out; - } - - counter = dbus_message_iter_get_uint32 (&iter); - - if (counter != data->counters[threadnr]) - { - g_print ("Thread %d, counter %d, expected %d\n", threadnr, counter, data->counters[threadnr]); - goto out; - } - data->counters[threadnr]++; - - if (! dbus_message_iter_next (&iter)) - { - g_print ("Couldn't get third arg\n"); - goto out; - } - - if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) - { - g_print ("Third arg not right type\n"); - goto out; - } - - str = dbus_message_iter_get_string (&iter); - - if (str == NULL) - { - g_print ("No third arg\n"); - goto out; - } - - expected_str = g_strdup_printf ("Thread %d-%d\n", threadnr, counter); - if (strcmp (expected_str, str) != 0) - { - g_print ("Wrong string '%s', expected '%s'\n", str, expected_str); - goto out; - } - g_free (str); - g_free (expected_str); - - if (dbus_message_iter_next (&iter)) - { - g_print ("Extra args on end of message\n"); - goto out; - } - - dbus_connection_flush (connection); - - counter_str = g_string_new (""); - for (i = 0; i < N_TEST_THREADS; i++) - { - g_string_append_printf (counter_str, "%d ", data->counters[i]); - } - g_print ("%s\r", counter_str->str); - g_string_free (counter_str, TRUE); - - out: - return DBUS_HANDLER_RESULT_HANDLED; -} - -static DBusHandlerResult -filter_disconnect (DBusConnection *connection, - DBusMessage *message, - void *user_data) -{ - if (!dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, - "Disconnected")) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - g_print ("connection disconnected\n"); - dbus_connection_unref (connection); - - return DBUS_HANDLER_RESULT_HANDLED; -} - -static void -new_connection_callback (DBusServer *server, - DBusConnection *new_connection, - void *user_data) -{ - ThreadTestData * data; - - g_print ("new_connection_callback\n"); - - dbus_connection_ref (new_connection); - dbus_connection_setup_with_g_main (new_connection, NULL); - - data = thread_test_data_new (); - - if (!dbus_connection_add_filter (new_connection, - filter_test_message, data, - (DBusFreeFunction) thread_test_data_free)) - goto nomem; - - if (!dbus_connection_add_filter (new_connection, - filter_disconnect, NULL, NULL)) - goto nomem; - - return; - - nomem: - g_error ("no memory to setup new connection"); -} - -int -main (int argc, char *argv[]) -{ - GMainLoop *loop; - DBusServer *server; - DBusError error; - - g_thread_init (NULL); - dbus_gthread_init (); - - if (argc < 2) - { - fprintf (stderr, "Give the server address as an argument\n"); - return 1; - } - - dbus_error_init (&error); - server = dbus_server_listen (argv[1], &error); - if (server == NULL) - { - fprintf (stderr, "Failed to start server on %s: %s\n", - argv[1], error.message); - dbus_error_free (&error); - return 1; - } - - dbus_server_set_new_connection_function (server, - new_connection_callback, - NULL, NULL); - - dbus_server_setup_with_g_main (server, NULL); - - loop = g_main_loop_new (NULL, FALSE); - g_main_run (loop); - - return 0; -} diff --git a/glib/test-thread.h b/glib/test-thread.h deleted file mode 100644 index 8c78fba2..00000000 --- a/glib/test-thread.h +++ /dev/null @@ -1 +0,0 @@ -#define N_TEST_THREADS 5 diff --git a/test/Makefile.am b/test/Makefile.am index 04df3510..ab04496e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,13 @@ +if HAVE_GLIB + GLIB_SUBDIR=glib +endif + +SUBDIRS=$(GLIB_SUBDIR) + INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS) + if DBUS_BUILD_TESTS TEST_BINARIES=test-service unbase64 break-loader spawn-test test-segfault test-exit test-sleep-forever else diff --git a/test/glib/Makefile.am b/test/glib/Makefile.am new file mode 100644 index 00000000..9f900b13 --- /dev/null +++ b/test/glib/Makefile.am @@ -0,0 +1,44 @@ +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) -I$(top_srcdir)/glib + +if DBUS_BUILD_TESTS + +if HAVE_GLIB_THREADS +THREAD_APPS=test-thread-server test-thread-client test-profile + +test_thread_server_SOURCES= \ + test-thread-server.c \ + test-thread.h + +test_thread_server_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la + +test_thread_client_SOURCES= \ + test-thread-client.c \ + test-thread.h + +test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la +endif + +## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we +## build even when not doing "make check" +noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS) + +test_dbus_glib_SOURCES= \ + test-dbus-glib.c + +test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la + +else +### not building tests + +if HAVE_GLIB_THREADS +noinst_PROGRAMS=test-profile +endif + +endif + +if HAVE_GLIB_THREADS +test_profile_SOURCES= \ + test-profile.c + +test_profile_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la +endif \ No newline at end of file diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c new file mode 100644 index 00000000..beda0a7a --- /dev/null +++ b/test/glib/test-dbus-glib.c @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +#include "dbus-glib.h" +#include + +int +main (int argc, char **argv) +{ + DBusConnection *connection; + DBusMessage *message, *reply; + GMainLoop *loop; + DBusError error; + + if (argc < 2) + { + g_printerr ("Give the server address as an argument\n"); + return 1; + } + + loop = g_main_loop_new (NULL, FALSE); + + dbus_error_init (&error); + connection = dbus_connection_open (argv[1], &error); + if (connection == NULL) + { + g_printerr ("Failed to open connection to %s: %s\n", argv[1], + error.message); + dbus_error_free (&error); + return 1; + } + + dbus_connection_setup_with_g_main (connection, NULL); + + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "Hello"); + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (reply == NULL) + { + g_printerr ("Error on hello message: %s\n", error.message); + dbus_error_free (&error); + return 1; + } + + g_print ("reply received\n"); + + g_main_loop_run (loop); + + return 0; +} diff --git a/test/glib/test-profile.c b/test/glib/test-profile.c new file mode 100644 index 00000000..6d9d8e7f --- /dev/null +++ b/test/glib/test-profile.c @@ -0,0 +1,226 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* test-profile.c Program that does basic message-response for timing + * + * 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 + * + */ + +/* FIXME this test is wacky since both client and server keep + * sending each other method calls, but nobody sends + * a DBUS_MESSAGE_TYPE_METHOD_RETURN + */ + +#include +#include +#include "dbus-glib.h" +#include + +#define N_CLIENT_THREADS 1 +#define N_ITERATIONS 1000 +#define PAYLOAD_SIZE 30 +#define ECHO_PATH "/org/freedesktop/EchoTest" +#define ECHO_INTERFACE "org.freedesktop.EchoTest" +#define ECHO_METHOD "EchoProfile" + +static const char *address; +static unsigned char *payload; + +static void +send_echo_message (DBusConnection *connection) +{ + DBusMessage *message; + + message = dbus_message_new_method_call (NULL, ECHO_PATH, + ECHO_INTERFACE, ECHO_METHOD); + dbus_message_append_args (message, + DBUS_TYPE_STRING, "Hello World!", + DBUS_TYPE_INT32, 123456, +#if 1 + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + payload, PAYLOAD_SIZE, +#endif + DBUS_TYPE_INVALID); + + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); + dbus_connection_flush (connection); +} + +static DBusHandlerResult +client_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + int *iterations = user_data; + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) + { + g_printerr ("Client thread disconnected\n"); + exit (1); + } + else if (dbus_message_is_method_call (message, + ECHO_INTERFACE, ECHO_METHOD)) + { + *iterations += 1; + if (*iterations >= N_ITERATIONS) + { + g_print ("Completed %d iterations\n", N_ITERATIONS); + exit (0); + } + send_echo_message (connection); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void* +thread_func (void *data) +{ + DBusError error; + GMainContext *context; + GMainLoop *loop; + DBusConnection *connection; + int iterations; + + g_printerr ("Starting client thread\n"); + + dbus_error_init (&error); + connection = dbus_connection_open (address, &error); + if (connection == NULL) + { + g_printerr ("could not open connection: %s\n", error.message); + dbus_error_free (&error); + exit (1); + } + + iterations = 1; + + if (!dbus_connection_add_filter (connection, + client_filter, &iterations, NULL)) + g_error ("no memory"); + + context = g_main_context_new (); + loop = g_main_loop_new (context, FALSE); + + dbus_connection_setup_with_g_main (connection, context); + + g_printerr ("Client thread sending message to prime pingpong\n"); + send_echo_message (connection); + g_printerr ("Client thread sent message\n"); + + g_printerr ("Client thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Client thread exiting main loop\n"); + + g_main_loop_unref (loop); + g_main_context_unref (context); + + return NULL; +} + +static DBusHandlerResult +server_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) + { + g_printerr ("Server thread disconnected\n"); + exit (1); + } + else if (dbus_message_is_method_call (message, + ECHO_INTERFACE, + ECHO_METHOD)) + { + send_echo_message (connection); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *user_data) +{ + dbus_connection_ref (new_connection); + dbus_connection_setup_with_g_main (new_connection, NULL); + + if (!dbus_connection_add_filter (new_connection, + server_filter, NULL, NULL)) + g_error ("no memory"); + + + /* FIXME we leak the handler */ +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusError error; + DBusServer *server; + int i; + + g_thread_init (NULL); + dbus_gthread_init (); + + dbus_error_init (&error); + server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, + &error); + if (server == NULL) + { + g_printerr ("Could not start server: %s\n", + error.message); + return 1; + } + + address = dbus_server_get_address (server); + payload = g_malloc (PAYLOAD_SIZE); + + dbus_server_set_new_connection_function (server, + new_connection_callback, + NULL, NULL); + + loop = g_main_loop_new (NULL, FALSE); + + dbus_server_setup_with_g_main (server, NULL); + + for (i = 0; i < N_CLIENT_THREADS; i++) + { + g_thread_create (thread_func, NULL, FALSE, NULL); + } + + g_printerr ("Server thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Server thread exiting main loop\n"); + + dbus_server_unref (server); + + g_main_loop_unref (loop); + + return 0; +} + diff --git a/test/glib/test-thread-client.c b/test/glib/test-thread-client.c new file mode 100644 index 00000000..d51d4e6a --- /dev/null +++ b/test/glib/test-thread-client.c @@ -0,0 +1,98 @@ +#include +#include "dbus-glib.h" +#include +#include +#include + +#include "test-thread.h" + +DBusConnection *connection; + +static gpointer +thread_func (gpointer data) +{ + gint32 threadnr = GPOINTER_TO_INT (data); + guint32 counter = 0; + DBusMessageIter iter; + DBusMessage *message; + char *str; + + while (1) + { + message = dbus_message_new_method_call (NULL, + "/org/freedesktop/ThreadTest", + "org.freedesktop.ThreadTest", + "TestMethod"); + + dbus_message_append_iter_init (message, &iter); + + if (!dbus_message_iter_append_int32 (&iter, threadnr)) + { + g_print ("thread %d: append threadnr failed\n", threadnr); + } + + if (!dbus_message_iter_append_uint32 (&iter, counter)) + { + g_print ("thread %d: append counter (%d) failed\n", threadnr, counter); + } + + str = g_strdup_printf ("Thread %d-%d\n", threadnr, counter); + if (!dbus_message_iter_append_string (&iter, str)) + { + g_print ("thread %d: append string (%s) failed\n", threadnr, str); + } + g_free (str); + + if (!dbus_connection_send (connection, + message, + NULL)) + { + g_print ("thread %d: send message failed\n", threadnr); + } + + dbus_message_unref (message); + + counter ++; + } + + return NULL; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusError error; + int i; + + g_thread_init (NULL); + dbus_gthread_init (); + + if(argc < 2) + { + g_error("Need an address as argv[1]\n"); + return 1; + } + + dbus_error_init (&error); + connection = dbus_connection_open (argv[1], &error); + if (connection == NULL) + { + g_printerr ("could not open connection: %s\n", error.message); + dbus_error_free (&error); + return 1; + } + + dbus_connection_setup_with_g_main (connection, NULL); + + for (i = 0; i < N_TEST_THREADS; i++) + { + g_thread_create (thread_func, GINT_TO_POINTER (i), FALSE, NULL); + } + + loop = g_main_loop_new (NULL, FALSE); + g_main_run (loop); + + return 0; +} + diff --git a/test/glib/test-thread-server.c b/test/glib/test-thread-server.c new file mode 100644 index 00000000..8898ca7f --- /dev/null +++ b/test/glib/test-thread-server.c @@ -0,0 +1,209 @@ +#include +#include "dbus-glib.h" +#include +#include + +#include "test-thread.h" + +typedef struct { + guint32 counters[N_TEST_THREADS]; +} ThreadTestData; + +static ThreadTestData * +thread_test_data_new (void) +{ + ThreadTestData *data; + + data = g_new0 (ThreadTestData, 1); + + return data; +} + +static void +thread_test_data_free (ThreadTestData *data) +{ + g_free (data); +} + +static DBusHandlerResult +filter_test_message (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + ThreadTestData *data = user_data; + DBusMessageIter iter; + gint32 threadnr; + guint32 counter; + char *str, *expected_str; + GString *counter_str; + int i; + + if (!dbus_message_is_method_call (message, "org.freedesktop.ThreadTest", + "TestMethod")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + dbus_message_iter_init (message, &iter); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32) + { + g_print ("First arg not right type\n"); + goto out; + } + threadnr = dbus_message_iter_get_int32 (&iter); + if (threadnr < 0 || threadnr >= N_TEST_THREADS) + { + g_print ("Invalid thread nr\n"); + goto out; + } + + if (! dbus_message_iter_next (&iter)) + { + g_print ("Couldn't get second arg\n"); + goto out; + } + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32) + { + g_print ("Second arg not right type\n"); + goto out; + } + + counter = dbus_message_iter_get_uint32 (&iter); + + if (counter != data->counters[threadnr]) + { + g_print ("Thread %d, counter %d, expected %d\n", threadnr, counter, data->counters[threadnr]); + goto out; + } + data->counters[threadnr]++; + + if (! dbus_message_iter_next (&iter)) + { + g_print ("Couldn't get third arg\n"); + goto out; + } + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) + { + g_print ("Third arg not right type\n"); + goto out; + } + + str = dbus_message_iter_get_string (&iter); + + if (str == NULL) + { + g_print ("No third arg\n"); + goto out; + } + + expected_str = g_strdup_printf ("Thread %d-%d\n", threadnr, counter); + if (strcmp (expected_str, str) != 0) + { + g_print ("Wrong string '%s', expected '%s'\n", str, expected_str); + goto out; + } + g_free (str); + g_free (expected_str); + + if (dbus_message_iter_next (&iter)) + { + g_print ("Extra args on end of message\n"); + goto out; + } + + dbus_connection_flush (connection); + + counter_str = g_string_new (""); + for (i = 0; i < N_TEST_THREADS; i++) + { + g_string_append_printf (counter_str, "%d ", data->counters[i]); + } + g_print ("%s\r", counter_str->str); + g_string_free (counter_str, TRUE); + + out: + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +filter_disconnect (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (!dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + g_print ("connection disconnected\n"); + dbus_connection_unref (connection); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *user_data) +{ + ThreadTestData * data; + + g_print ("new_connection_callback\n"); + + dbus_connection_ref (new_connection); + dbus_connection_setup_with_g_main (new_connection, NULL); + + data = thread_test_data_new (); + + if (!dbus_connection_add_filter (new_connection, + filter_test_message, data, + (DBusFreeFunction) thread_test_data_free)) + goto nomem; + + if (!dbus_connection_add_filter (new_connection, + filter_disconnect, NULL, NULL)) + goto nomem; + + return; + + nomem: + g_error ("no memory to setup new connection"); +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusServer *server; + DBusError error; + + g_thread_init (NULL); + dbus_gthread_init (); + + if (argc < 2) + { + fprintf (stderr, "Give the server address as an argument\n"); + return 1; + } + + dbus_error_init (&error); + server = dbus_server_listen (argv[1], &error); + if (server == NULL) + { + fprintf (stderr, "Failed to start server on %s: %s\n", + argv[1], error.message); + dbus_error_free (&error); + return 1; + } + + dbus_server_set_new_connection_function (server, + new_connection_callback, + NULL, NULL); + + dbus_server_setup_with_g_main (server, NULL); + + loop = g_main_loop_new (NULL, FALSE); + g_main_run (loop); + + return 0; +} diff --git a/test/glib/test-thread.h b/test/glib/test-thread.h new file mode 100644 index 00000000..8c78fba2 --- /dev/null +++ b/test/glib/test-thread.h @@ -0,0 +1 @@ +#define N_TEST_THREADS 5 -- cgit v1.2.1 From d7f8a9510f0987245a7473151dff7bfdd318d7fd Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 5 Sep 2003 04:14:15 +0000 Subject: more missing files --- glib/dbus-gtest-main.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ glib/dbus-gtool-test.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 glib/dbus-gtest-main.c create mode 100644 glib/dbus-gtool-test.h diff --git a/glib/dbus-gtest-main.c b/glib/dbus-gtest-main.c new file mode 100644 index 00000000..5cc6cb78 --- /dev/null +++ b/glib/dbus-gtest-main.c @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gtest-main.c Program to run all libdbus-glib tests + * + * 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-gtest.h" +#include +#include +#include + +int +main (int argc, + char **argv) +{ + const char *test_data_dir; + + setlocale(LC_ALL, ""); + + + if (argc > 1) + test_data_dir = argv[1]; + else + test_data_dir = NULL; + + dbus_glib_internal_do_not_use_run_tests (test_data_dir); + + return 0; +} diff --git a/glib/dbus-gtool-test.h b/glib/dbus-gtool-test.h new file mode 100644 index 00000000..74a7649f --- /dev/null +++ b/glib/dbus-gtool-test.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gtool-test.h Declarations of test functions for dbus-glib-tool. + * + * 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_GLIB_TOOL_TEST_H +#define DBUS_GLIB_TOOL_TEST_H + +#include "dbus-glib.h" + +dbus_bool_t _dbus_gtool_test (const char *test_data_dir); + +#endif /* DBUS_GLIB_TEST_H */ -- cgit v1.2.1 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 --- ChangeLog | 6 ++++++ dbus/dbus-connection.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- dbus/dbus-connection.h | 4 ++++ dbus/dbus-object-tree.c | 37 ++++++++++++++++++++++++++++--------- dbus/dbus-object-tree.h | 1 + 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index ccca8a8e..a9328da2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +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 + 2003-09-03 Havoc Pennington * test/glib/Makefile.am: add this with random glib-linked test 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 v1.2.1 From 83e41dff82abe99e1a35e70ca0bb60672204ffcd Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 6 Sep 2003 21:12:11 +0000 Subject: 2003-09-06 Havoc Pennington * doc/dbus-specification.sgml: partial updates * bus/dbus-daemon-1.1.in: fix the config file docs for the zillionth time; hopefully I edited the right file this time. * bus/config-parser.c (append_rule_from_element): support send_type, send_path, receive_type, receive_path * bus/policy.c: add message type and path to the list of things that can be "firewalled" --- ChangeLog | 13 +++ bus/config-parser.c | 119 +++++++++++++++++++++++---- bus/dbus-daemon-1.1.in | 61 ++++++++++---- bus/policy.c | 50 +++++++++++ bus/policy.h | 6 ++ doc/dbus-specification.sgml | 53 ++++++++---- test/data/valid-config-files/many-rules.conf | 57 +++++++++++++ 7 files changed, 309 insertions(+), 50 deletions(-) create mode 100644 test/data/valid-config-files/many-rules.conf diff --git a/ChangeLog b/ChangeLog index a9328da2..1e60a09e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2003-09-06 Havoc Pennington + + * doc/dbus-specification.sgml: partial updates + + * bus/dbus-daemon-1.1.in: fix the config file docs for the + zillionth time; hopefully I edited the right file this time. + + * bus/config-parser.c (append_rule_from_element): support + send_type, send_path, receive_type, receive_path + + * bus/policy.c: add message type and path to the list of things + that can be "firewalled" + 2003-09-06 Havoc Pennington * dbus/dbus-connection.c (dbus_connection_register_fallback): add this diff --git a/bus/config-parser.c b/bus/config-parser.c index 471c67d8..2a7d0752 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -808,6 +808,21 @@ start_busconfig_child (BusConfigParser *parser, } } +static int +message_type_from_string (const char *type_str) +{ + if (strcmp (type_str, "method_call") == 0) + return DBUS_MESSAGE_TYPE_METHOD_CALL; + if (strcmp (type_str, "method_return") == 0) + return DBUS_MESSAGE_TYPE_METHOD_RETURN; + else if (strcmp (type_str, "signal") == 0) + return DBUS_MESSAGE_TYPE_SIGNAL; + else if (strcmp (type_str, "error") == 0) + return DBUS_MESSAGE_TYPE_ERROR; + else + return DBUS_MESSAGE_TYPE_INVALID; +} + static dbus_bool_t append_rule_from_element (BusConfigParser *parser, const char *element_name, @@ -820,10 +835,14 @@ append_rule_from_element (BusConfigParser *parser, const char *send_member; const char *send_error; const char *send_service; + const char *send_path; + const char *send_type; const char *receive_interface; const char *receive_member; const char *receive_error; const char *receive_service; + const char *receive_path; + const char *receive_type; const char *own; const char *user; const char *group; @@ -837,10 +856,14 @@ append_rule_from_element (BusConfigParser *parser, "send_member", &send_member, "send_error", &send_error, "send_service", &send_service, + "send_path", &send_path, + "send_type", &send_type, "receive_interface", &receive_interface, "receive_member", &receive_member, "receive_error", &receive_error, "receive_service", &receive_service, + "receive_path", &receive_path, + "receive_type", &receive_type, "own", &own, "user", &user, "group", &group, @@ -848,7 +871,9 @@ append_rule_from_element (BusConfigParser *parser, return FALSE; if (!(send_interface || send_member || send_error || send_service || + send_type || send_path || receive_interface || receive_member || receive_error || receive_service || + receive_type || receive_path || own || user || group)) { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -857,11 +882,11 @@ append_rule_from_element (BusConfigParser *parser, return FALSE; } - if ((send_member && send_interface == NULL) || - (receive_member && receive_interface == NULL)) + if ((send_member && (send_interface == NULL && send_path == NULL)) || + (receive_member && (receive_interface == NULL && receive_path == NULL))) { dbus_set_error (error, DBUS_ERROR_FAILED, - "On element <%s>, if you specify a member you must specify an interface", + "On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.", element_name); return FALSE; } @@ -869,12 +894,13 @@ append_rule_from_element (BusConfigParser *parser, /* Allowed combinations of elements are: * * base, must be all send or all receive: + * nothing * interface * interface + member * error * - * base send_ can combine with send_service, - * base receive_ with receive_service + * base send_ can combine with send_service, send_path, send_type + * base receive_ with receive_service, receive_path, receive_type * * user, group, own must occur alone */ @@ -913,6 +939,22 @@ append_rule_from_element (BusConfigParser *parser, (send_service && user) || (send_service && group)) || + ((send_type && receive_interface) || + (send_type && receive_member) || + (send_type && receive_error) || + (send_type && receive_service) || + (send_type && own) || + (send_type && user) || + (send_type && group)) || + + ((send_path && receive_interface) || + (send_path && receive_member) || + (send_path && receive_error) || + (send_path && receive_service) || + (send_path && own) || + (send_path && user) || + (send_path && group)) || + ((receive_interface && receive_error) || (receive_interface && own) || (receive_interface && user) || @@ -938,7 +980,7 @@ append_rule_from_element (BusConfigParser *parser, element_name); return FALSE; } - + rule = NULL; /* In BusPolicyRule, NULL represents wildcard. @@ -946,11 +988,10 @@ append_rule_from_element (BusConfigParser *parser, */ #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') - if (send_interface || send_member || send_error || send_service) + if (send_interface || send_member || send_error || send_service || + send_path || send_type) { - rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); - if (rule == NULL) - goto nomem; + int message_type; if (IS_WILDCARD (send_interface)) send_interface = NULL; @@ -960,11 +1001,36 @@ append_rule_from_element (BusConfigParser *parser, send_error = NULL; if (IS_WILDCARD (send_service)) send_service = NULL; + if (IS_WILDCARD (send_path)) + send_path = NULL; + if (IS_WILDCARD (send_type)) + send_type = NULL; + + message_type = DBUS_MESSAGE_TYPE_INVALID; + if (send_type != NULL) + { + message_type = message_type_from_string (send_type); + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad message type \"%s\"", + send_type); + return FALSE; + } + } + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); + if (rule == NULL) + goto nomem; + + rule->d.send.message_type = message_type; + rule->d.send.path = _dbus_strdup (send_path); rule->d.send.interface = _dbus_strdup (send_interface); rule->d.send.member = _dbus_strdup (send_member); rule->d.send.error = _dbus_strdup (send_error); rule->d.send.destination = _dbus_strdup (send_service); + if (send_path && rule->d.send.path == NULL) + goto nomem; if (send_interface && rule->d.send.interface == NULL) goto nomem; if (send_member && rule->d.send.member == NULL) @@ -974,11 +1040,10 @@ append_rule_from_element (BusConfigParser *parser, if (send_service && rule->d.send.destination == NULL) goto nomem; } - else if (receive_interface || receive_member || receive_error || receive_service) + else if (receive_interface || receive_member || receive_error || receive_service || + receive_path || receive_type) { - rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); - if (rule == NULL) - goto nomem; + int message_type; if (IS_WILDCARD (receive_interface)) receive_interface = NULL; @@ -988,11 +1053,37 @@ append_rule_from_element (BusConfigParser *parser, receive_error = NULL; if (IS_WILDCARD (receive_service)) receive_service = NULL; + if (IS_WILDCARD (receive_path)) + receive_path = NULL; + if (IS_WILDCARD (receive_type)) + receive_type = NULL; + + + message_type = DBUS_MESSAGE_TYPE_INVALID; + if (receive_type != NULL) + { + message_type = message_type_from_string (receive_type); + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad message type \"%s\"", + receive_type); + return FALSE; + } + } + + rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); + if (rule == NULL) + goto nomem; + rule->d.receive.message_type = message_type; + rule->d.receive.path = _dbus_strdup (receive_path); rule->d.receive.interface = _dbus_strdup (receive_interface); rule->d.receive.member = _dbus_strdup (receive_member); rule->d.receive.error = _dbus_strdup (receive_error); rule->d.receive.origin = _dbus_strdup (receive_service); + if (receive_path && rule->d.receive.path == NULL) + goto nomem; if (receive_interface && rule->d.receive.interface == NULL) goto nomem; if (receive_member && rule->d.receive.member == NULL) diff --git a/bus/dbus-daemon-1.1.in b/bus/dbus-daemon-1.1.in index 73a88c90..ec915edd 100644 --- a/bus/dbus-daemon-1.1.in +++ b/bus/dbus-daemon-1.1.in @@ -333,11 +333,22 @@ in the config file. A element appears below a element and prohibits some action. The possible attributes of a element are: .nf - send="messagename" + send_interface="interface_name" + send_member="method_or_signal_name" + send_error="error_name" + send_service="service_name" + send_type="method_call|method_return|signal|error" + send_path="/path/name" + + receive_interface="interface_name" + receive_member="method_or_signal_name" + receive_error="error_name" + receive_service="service_name" + receive_type="method_call|method_return|signal|error" + receive_path="/path/name" + receive="messagename" own="servicename" - send_to="servicename" - receive_from="servicename" user="username" group="groupname" .fi @@ -345,11 +356,11 @@ some action. The possible attributes of a element are: .PP Examples: .nf - - + + - - + + .fi @@ -360,18 +371,22 @@ particular action. If it matches, the action is denied (unless later rules in the config file allow it). .PP -send_to and receive_from mean that messages may not be sent to or -received from the *owner* of the given service, not that they may not -be sent *to that service name*. That is, if a connection owns services -A, B, C, and sending to A is denied, sending to B or C will not work -either. +send_service and receive_service rules mean that messages may not be +sent to or received from the *owner* of the given service, not that +they may not be sent *to that service name*. That is, if a connection +owns services A, B, C, and sending to A is denied, sending to B or C +will not work either. + +.PP +The other send_* and receive_* attributes are purely textual/by-value +matches against the given field in the message header. .PP user and group denials mean that the given user or group may not connect to the message bus. .PP -For "servicename" or "messagename" or "username" or "groupname" +For "service_name", "username", "groupname", etc. the character "*" can be substituted, meaning "any." Complex globs like "foo.bar.*" aren't allowed for now because they'd be work to implement and maybe encourage sloppy security anyway. @@ -382,11 +397,21 @@ for a user or group; user/group denials can only be inside context="default" or context="mandatory" policies. .PP -A single rule may specify both send and send_to, OR both -receive and receive_from. In this case, the denial applies only if -both attributes match the message being denied. -e.g. would deny -messages of the given name AND to the given service. +A single rule may specify combinations of attributes such as +send_service and send_interface and send_type. In this case, the +denial applies only if both attributes match the message being denied. +e.g. would +deny messages of the given interface AND to the given service. +To get an OR effect you specify multiple rules. + +.PP +You can't include both send_ and receive_ attributes on the same +rule, since "whether the message can be sent" and "whether it can be +received" are evaluated separately. + +.PP +Be careful with send_interface/receive_interface, because the +interface field in messages is optional. .TP .I "" diff --git a/bus/policy.c b/bus/policy.c index f7978c05..21d0b02e 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -52,7 +52,11 @@ bus_policy_rule_new (BusPolicyRuleType type, rule->d.group.gid = DBUS_GID_UNSET; break; case BUS_POLICY_RULE_SEND: + rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID; + break; case BUS_POLICY_RULE_RECEIVE: + rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID; + break; case BUS_POLICY_RULE_OWN: break; } @@ -80,12 +84,14 @@ bus_policy_rule_unref (BusPolicyRule *rule) switch (rule->type) { case BUS_POLICY_RULE_SEND: + dbus_free (rule->d.send.path); dbus_free (rule->d.send.interface); dbus_free (rule->d.send.member); dbus_free (rule->d.send.error); dbus_free (rule->d.send.destination); break; case BUS_POLICY_RULE_RECEIVE: + dbus_free (rule->d.receive.path); dbus_free (rule->d.receive.interface); dbus_free (rule->d.receive.member); dbus_free (rule->d.receive.error); @@ -717,6 +723,8 @@ bus_client_policy_optimize (BusClientPolicy *policy) { case BUS_POLICY_RULE_SEND: remove_preceding = + rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID && + rule->d.send.path == NULL && rule->d.send.interface == NULL && rule->d.send.member == NULL && rule->d.send.error == NULL && @@ -724,6 +732,8 @@ bus_client_policy_optimize (BusClientPolicy *policy) break; case BUS_POLICY_RULE_RECEIVE: remove_preceding = + rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID && + rule->d.receive.path == NULL && rule->d.receive.interface == NULL && rule->d.receive.member == NULL && rule->d.receive.error == NULL && @@ -799,6 +809,26 @@ bus_client_policy_check_can_send (BusClientPolicy *policy, continue; } + if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID) + { + if (dbus_message_get_type (message) != rule->d.send.message_type) + { + _dbus_verbose (" (policy) skipping rule for different message type\n"); + continue; + } + } + + if (rule->d.send.path != NULL) + { + if (dbus_message_get_path (message) != NULL && + strcmp (dbus_message_get_path (message), + rule->d.send.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + continue; + } + } + if (rule->d.send.interface != NULL) { if (dbus_message_get_interface (message) != NULL && @@ -911,6 +941,26 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, _dbus_verbose (" (policy) skipping non-receive rule\n"); continue; } + + if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID) + { + if (dbus_message_get_type (message) != rule->d.receive.message_type) + { + _dbus_verbose (" (policy) skipping rule for different message type\n"); + continue; + } + } + + if (rule->d.receive.path != NULL) + { + if (dbus_message_get_path (message) != NULL && + strcmp (dbus_message_get_path (message), + rule->d.receive.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + continue; + } + } if (rule->d.receive.interface != NULL) { diff --git a/bus/policy.h b/bus/policy.h index 2aa69aaf..5824816c 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -54,7 +54,10 @@ struct BusPolicyRule { struct { + /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */ + int message_type; /* any of these can be NULL meaning "any" */ + char *path; char *interface; char *member; char *error; @@ -63,7 +66,10 @@ struct BusPolicyRule struct { + /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */ + int message_type; /* any of these can be NULL meaning "any" */ + char *path; char *interface; char *member; char *error; diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index 031bb329..7800165b 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -3,8 +3,8 @@
D-BUS Specification - Version 0.7 - 26 March 2003 + Version 0.8 + 06 September 2003 Havoc @@ -65,10 +65,10 @@ D-BUS is easy to use because it works in terms of messages rather than byte streams, and - does not require users to understand any complex concepts such as a - new type system or elaborate APIs. Libraries implementing D-BUS - may choose to abstract messages as "method calls" (see - ). + automatically handles a lot of the hard IPC issues. Also, the D-BUS + library is designed to be wrapped in a way that lets users use their + framework's existing object/type system, rather than learning a new + one specifically for IPC. @@ -83,11 +83,10 @@ forwards messages among them. - Things that D-BUS can be used for is for example notification of - system changes (notification of when a camera is plugged in to a - computer, or a new version of some software has been installed), - or desktop interoperablity, for example a file monitoring - service or a configuration service. + Uses of D-BUS include notification of system changes (notification of when + a camera is plugged in to a computer, or a new version of some software + has been installed), or desktop interoperablity, for example a file + monitoring service or a configuration service. @@ -279,9 +278,27 @@ - name + path STRING - The name of the message, such as org.freedesktop.Peer.Ping + The object to send the message to; objects are identified by + a path, "/foo/bar" + + + ifce + STRING + The interface to invoke a method call on, or + that a signal is emitted from. e.g. "org.freedesktop.Introspectable" + + + mebr + STRING + The member, either the method name or signal name. + e.g. "Frobate" + + + ernm + STRING + The name of the error that occurred, for errors rply @@ -298,10 +315,10 @@ . - sndr + sdrs STRING - The name of the base service that sent this message. - The message bus fills in this field; the field is + Sender service. The name of the base service that sent + this message. The message bus fills in this field; the field is only meaningful in combination with the message bus. @@ -480,9 +497,9 @@ Valid names - Messages and services have names with type STRING, meaning that + Services have names with type STRING, meaning that they must be valid UTF-8. However, there are also some - additional restrictions that apply to message and service names + additional restrictions that apply to service names specifically: They must contain at least one '.' (period) character diff --git a/test/data/valid-config-files/many-rules.conf b/test/data/valid-config-files/many-rules.conf new file mode 100644 index 00000000..57ea5ec9 --- /dev/null +++ b/test/data/valid-config-files/many-rules.conf @@ -0,0 +1,57 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + nonexistent.conf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5000 + 5000 + 300 + 5000 + 6000 + 50 + 80 + 64 + 64 + 256 + + -- cgit v1.2.1 From b8e4216fecda267db8304494f52a0da5e6f3e0ae Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 7 Sep 2003 05:01:48 +0000 Subject: 2003-09-07 Havoc Pennington * doc/dbus-specification.sgml: more updates --- ChangeLog | 4 + doc/dbus-specification.sgml | 460 +++++++++++++++++++++++++++----------------- 2 files changed, 284 insertions(+), 180 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1e60a09e..908229a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-09-07 Havoc Pennington + + * doc/dbus-specification.sgml: more updates + 2003-09-06 Havoc Pennington * doc/dbus-specification.sgml: partial updates diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index 7800165b..5d2982fc 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -66,9 +66,9 @@ D-BUS is easy to use because it works in terms of messages rather than byte streams, and automatically handles a lot of the hard IPC issues. Also, the D-BUS - library is designed to be wrapped in a way that lets users use their - framework's existing object/type system, rather than learning a new - one specifically for IPC. + library is designed to be wrapped in a way that lets developers use + their framework's existing object/type system, rather than learning + a new one specifically for IPC. @@ -171,9 +171,11 @@ 4 bytes The message's serial number, an unsigned 32-bit integer in - the message's byte order. Applications MUST NOT reuse the same - serial number for different messages more often than 32-bit - unsigned integer wraparound. Zero is not a valid serial number. + the message's byte order. The serial number is a cookie used to + identify message replies; thus all outstanding unreplied-to messages + from the same connection MUST have a different serial number. + Zero is not a valid serial number, but all other numbers are + allowed. @@ -183,33 +185,39 @@ Types that can appear in the second byte of the header: - + + Conventional name Decimal value Description + INVALID 0 This is an invalid type, if seen in a message the connection should be dropped immediately. + METHOD_CALL 1 Method call. + METHOD_RETURN 2 Method reply with returned data. + ERROR 3 Error reply. If the first argument exists and is a string, it is an error message. + SIGNAL 4 Signal emission. @@ -220,15 +228,17 @@ Flags that can appear in the third byte of the header: - + + Conventional name Hex value Description + NO_REPLY_EXPECTED 0x1 This message does not expect method return replies or error replies; the reply can be omitted as an @@ -497,19 +507,228 @@ Valid names - Services have names with type STRING, meaning that - they must be valid UTF-8. However, there are also some - additional restrictions that apply to service names - specifically: - - They must contain at least one '.' (period) character - They must not begin with a '.' (period) character - They must not exceed 256 bytes in length - They must be at least 1 byte in length - - As a special exception, base service names (those beginning with a colon (':') character) - need not contain a period. + The various header fields of type STRING have some restrictions + on the string's format. + + Service names + + Services have names with type STRING, meaning that + they must be valid UTF-8. However, there are also some + additional restrictions that apply to service names + specifically: + + They must contain at least one '.' (period) character + They must not begin with a '.' (period) character + They must not exceed 256 bytes in length + They must be at least 1 byte in length + + + As a special exception, base service names (those beginning with a colon + (':') character) need not contain a period. + + + FIXME really, shouldn't we ban basically everything non-alphanumeric + so the name will work in all programming languages? + + + + Interface names + + Interface names have the same restrictions as service names, + but do not have the special exception for names beginning with + a colon. + + + FIXME really, shouldn't we ban basically everything non-alphanumeric + so the name will work in all programming languages? + + + + Method names + + Method names: + + May not contain the '.' (period) character + Must not exceed 256 bytes in length + Must be at least 1 byte in length + + + + FIXME really, shouldn't we ban basically everything non-alphanumeric + so the name will work in all programming languages? + + + + Path names + + A path must begin with an ASCII '/' (slash) character. Paths may not + end with a slash character unless the path is the one-byte string + "/". Two slash characters may not appear adjacent to one another (the + empty string is not a valid "subdirectory"). Paths may not exceed + 256 bytes in length. + + + + Error names + + Error names have the same restrictions as interface names. + + + FIXME really, shouldn't we ban basically everything non-alphanumeric + so the name will work in all programming languages? + + + + + + Message types + + Each of the message types (METHOD_CALL, METHOD_RETURN, ERROR, and + SIGNAL) has its own expected usage conventions and header fields. + + + Method Calls, Returns, and Errors + + Some messages invoke an operation on a remote object. These are + called method call messages and have the type tag METHOD_CALL. Such + messages map naturally to methods on objects in a typical program. + + + A method call message is expected to have a 'mebr' header field + indicating the name of the method. Optionally, the message has an + 'ifce' field giving the interface the method is a part of. In the + absence of an 'ifce' field, if two interfaces on the same object have + a method with the same name, it is undefined which of the two methods + will be invoked. Implementations may also choose to return an error in + this ambiguous case. However, if a method name is unique + implementations should not require an interface field. + + + Method call messages also include a 'path' field indicating the + object to invoke the method on. If the call is passing through + a message bus, the message will also have a 'srvc' field giving + the service to receive the message. + + + When an application handles a method call message, it is expected to + return a reply. The reply is identified by a 'rply' header field + indicating the serial number of the METHOD_CALL being replied to. The + reply can have one of two types; either METHOD_RETURN or ERROR. + + + If the reply has type METHOD_RETURN, the arguments to the reply message + are the return value(s) or "out parameters" of the method call. + If the reply has type ERROR, then an "exception" has been thrown, + and the call fails; no return value will be provided. It makes + no sense to send multiple replies to the same method call. + + + Even if a method call has no return values, a METHOD_RETURN + reply is expected, so the caller will know the method + was successfully processed. + + + If a METHOD_CALL message has the flag NO_REPLY_EXPECTED, + then as an optimization the application receiving the method + call may choose to omit the reply message (regardless of + whether the reply would have been METHOD_RETURN or ERROR). + However, it is also acceptable to ignore the NO_REPLY_EXPECTED + flag and reply anyway. + + + Mapping method calls to native APIs + + APIs for D-BUS may map method calls to a method call in a specific + programming language, such as C++, or may map a method call written + in an IDL to a D-BUS message. + + + In APIs of this nature, arguments to a method are often termed "in" + (which implies sent in the METHOD_CALL), or "out" (which implies + returned in the METHOD_RETURN). Some APIs such as CORBA also have + "inout" arguments, which are both sent and received, i.e. the caller + passes in a value which is modified. Mapped to D-BUS, an "inout" + argument is equivalent to an "in" argument, followed by an "out" + argument. You can't pass things "by reference" over the wire, so + "inout" is purely an illusion of the in-process API. + + + Given a method with zero or one return values, followed by zero or more + arguments, where each argument may be "in", "out", or "inout", the + caller constructs a message by appending each "in" or "inout" argument, + in order. "out" arguments are not represented in the caller's message. + + + The recipient constructs a reply by appending first the return value + if any, then each "out" or "inout" argument, in order. + "in" arguments are not represented in the reply message. + + + + + + + Signal Emission + + Unlike method calls, signal emissions have no replies. + A signal emission is simply a single message of type SIGNAL. + It must have three header fields: 'path' giving the object + the signal was emitted from, plus 'ifce' and 'mebr' giving the + fully-qualified name of the signal. + + + + + Notation in this document + + This document uses a simple pseudo-IDL to describe particular method + calls and signals. Here is an example of a method call: + + org.freedesktop.DBus.ActivateService (in STRING service_name, in UINT32 flags, + out UINT32 resultcode) + + This means ifce = org.freedesktop.DBus, mebr = ActivateService, + METHOD_CALL arguments are STRING and UINT32, METHOD_RETURN argument + is UINT32. Remember that the 'mebr' field can't contain any '.' (period) + characters so it's known that the last part of the name in + the "IDL" is the member name. + + + In C++ that might end up looking like this: + + unsigned int org::freedesktop::DBus::ActivateService (const char *service_name, + unsigned int flags); + + or equally valid, the return value could be done as an argument: + + void org::freedesktop::DBus::ActivateService (const char *service_name, + unsigned int flags, + unsigned int *resultcode); + + It's really up to the API designer how they want to make + this look. You could design an API where the namespace wasn't used + in C++, using STL or Qt, using varargs, or whatever you wanted. + + + Signals are written as follows: + + org.freedesktop.DBus.ServiceLost (STRING service_name) + + Signals don't specify "in" vs. "out" because only + a single direction is possible. + + + In this ad hoc notation, the special type name ANY means any type + other than NIL, and the special type name ANY_OR_NIL means any valid + type. + + + It isn't especially encouraged to use this lame pseudo-IDL in actual + API implementations; you might use the native notation for the + language you're using, or you might use COM or CORBA IDL, for example. + + @@ -969,161 +1188,35 @@ - - Message Conventions - - This section documents conventions that are not essential to D-BUS - functionality, but should generally be followed in order to simplify - programmer's lives. - - - Message Naming - - Messages are normally named in the form - "org.freedesktop.Peer.Ping", which has three - distinct components: - - - Namespace e.g. org.freedesktop - - - Message names have a Java-style namespace: a reversed domain - name. The components of the domain are normally lowercase. - - - - - Package or object e.g. Peer - - - The next part of the message name can be thought of as the name - of a singleton object, or as the name of a package of related - messages. More than one dot-separated component might be used - here. (Note that D-BUS does not define any idea of object - instances or object references.) The package or object name is - capitalized LikeThis. - - - - - Method or operation e.g. Ping - - - The final part of the message name is the most specific, and - should be a verb indicating an operation to be performed on the - object. The method or operation name is capitalized LikeThis. - - - - - - - A reply to a message conventionally has the same name as the message - being replied to. When following method call conventions (see ), this convention is mandatory, - because a message with multiple possible replies can't be mapped - to method call semantics without special-case code. - - - - Method Call Mapping - - Some implementations of D-BUS may present an API that translates object - method calls into D-BUS messages. This document does not specify in - detail how such an API should look or work. However, it does specify how - message-based protocols should be designed to be friendly to such an - API. - - - Remember that D-BUS does not have object references or object instances. - So when one application sends the message - org.freedesktop.Peer.Ping, it sends it to another - application, not to any kind of sub-portion of that application. - However, a convenience API used within the recipient application may - route all messages that start with - org.freedesktop.Peer to a particular object instance, - and may invoke the Ping() method on said instance in - order to handle the message. This is a convenience API based on - method calls. - - - A "method call" consists of a message and, optionally, a reply to that - message. The name of the "method" is the last component of the message, - for example, org.freedesktop.Peer.Ping would map to - the method Ping() on some object. - - - Arguments to a method may be considered "in" (processed by the - recipient of the message), or "out" (returned to the sender of the - message in the reply). "inout" arguments are both sent and received, - i.e. the caller passes in a value which is modified. An "inout" argument - is equivalent to an "in" argument, followed by an "out" argument. - - - Given a method with zero or one return values, followed by zero or more - arguments, where each argument may be "in", "out", or "inout", the - caller constructs a message by appending each "in" or "inout" argument, - in order. "out" arguments are not represented in the caller's message. - - - The recipient constructs a reply by appending first the return value - if any, then each "out" or "inout" argument, in order. - "in" arguments are not represented in the reply message. - - - The standard reply message MUST have the same name as the message being - replied to, and MUST set the "rply" header field to the serial - number of the message being replied to. - - - If an error occurs, an error reply may be sent in place of the standard - reply. Error replies can be identified by a special header flag, see - . Error replies have a - name which reflects the type of error that occurred. Error replies would - generally be mapped to exceptions in a programming language. If an - error reply has a first argument, and that argument has type STRING, - then the argument must be an error message. - - - [FIXME discuss mapping of broadcast messages + matching rules - to signals and slots] - - - - Standard Peer-to-Peer Messages - In the following message definitions, "method call notation" is presented - in addition to simply listing the message names and arguments. The special - type name ANY means any type other than NIL, and the special type name - ANY_OR_NIL means any valid type. - [FIXME the messages here are just made up to illustrate the - format for defining them] + See for details on + the notation used in this section. <literal>org.freedesktop.Peer.Ping</literal> - As a method: - void Ping () + org.freedesktop.Peer.Ping () - On receipt of the message org.freedesktop.Peer.Ping, - an application should reply with - org.freedesktop.Peer.Ping. Neither the - message nor its reply have any arguments. - [FIXME the messages here are just made up to illustrate the - format for defining them] + On receipt of the METHOD_CALL + message org.freedesktop.Peer.Ping, an application + should do nothing other than reply with a METHOD_RETURN as usual. + <literal>org.freedesktop.Props.Get</literal> - As a method: + [FIXME this is just a bogus made-up method that isn't implemented + or thought through, to save an example of table formatting for the + argument descriptions] - ANY_OR_NIL Get (in STRING property_name) + org.freedesktop.Props.Get (in STRING property_name, + out ANY_OR_NIL property_value) Message arguments: @@ -1138,37 +1231,18 @@ 0 - STRING + in STRING Name of the property to get - - - - Reply arguments: - - - - Argument - Type - Description - - - - - 0 - ANY_OR_NIL + 1 + out ANY_OR_NIL The value of the property. The type depends on the property. - - - [FIXME the messages here are just made up to illustrate the - format for defining them] - @@ -2009,6 +2083,32 @@ + + Object + + + Each application contains objects, + which have interfaces and + methods. Objects are referred to + by a name, called a path or + object reference. + + + + + Path + + + Object references (object names) in D-BUS are + organized into a filesystem-style hierarchy, so + each object is named by a path. As in LDAP, + there's no difference between "files" and "directories"; + a path can refer to an object, while still having + child objects below it. + + + + Peer-to-peer -- cgit v1.2.1 From 42c7c17953840ee12e482f6716c4ff03c136f6b5 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sun, 7 Sep 2003 14:22:25 +0000 Subject: Add this --- test/glib/.cvsignore | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 test/glib/.cvsignore diff --git a/test/glib/.cvsignore b/test/glib/.cvsignore new file mode 100644 index 00000000..2e6b67f0 --- /dev/null +++ b/test/glib/.cvsignore @@ -0,0 +1,9 @@ +.deps +.libs +Makefile +Makefile.in +test-dbus-glib +test-profile +test-thread-server +test-thread-client + -- cgit v1.2.1 From 32bd6660e07696ed99bfa60b08700e8eae3e96b1 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sun, 7 Sep 2003 16:21:12 +0000 Subject: Update --- glib/.cvsignore | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/glib/.cvsignore b/glib/.cvsignore index a6e3d2b5..881b4887 100644 --- a/glib/.cvsignore +++ b/glib/.cvsignore @@ -4,11 +4,9 @@ Makefile Makefile.in *.lo *.la -test-dbus-glib +dbus-glib-test +dbus-glib-tool *.bb *.bbg *.da *.gcov -test-thread-client -test-thread-server -test-profile -- cgit v1.2.1 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. --- ChangeLog | 4 ++ Doxyfile.in | 2 +- bus/config-parser.c | 5 ++- bus/desktop-file.c | 14 ++++--- bus/services.c | 8 +++- 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 ++ glib/dbus-gidl.c | 4 ++ glib/dbus-gidl.h | 4 ++ glib/dbus-glib.h | 23 +++++++---- glib/dbus-gloader-expat.c | 13 ++++--- glib/dbus-gmain.c | 3 ++ glib/dbus-gparser.c | 4 ++ glib/dbus-gproxy.c | 17 ++++++--- 43 files changed, 443 insertions(+), 207 deletions(-) diff --git a/ChangeLog b/ChangeLog index 908229a8..a4dba23f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-09-07 Havoc Pennington + + * Make Doxygen contented. + 2003-09-07 Havoc Pennington * doc/dbus-specification.sgml: more updates diff --git a/Doxyfile.in b/Doxyfile.in index b2ac9587..9648449a 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -49,7 +49,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = dbus bus glib +INPUT = dbus glib FILE_PATTERNS = *.c *.h RECURSIVE = YES #EXCLUDE = test diff --git a/bus/config-parser.c b/bus/config-parser.c index 2a7d0752..cbc239f9 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -88,9 +88,12 @@ typedef struct } Element; +/** + * Parser for bus configuration file. + */ struct BusConfigParser { - int refcount; + int refcount; /**< Reference count */ DBusString basedir; /**< Directory we resolve paths relative to */ diff --git a/bus/desktop-file.c b/bus/desktop-file.c index 08af768e..dd621214 100644 --- a/bus/desktop-file.c +++ b/bus/desktop-file.c @@ -48,15 +48,19 @@ struct BusDesktopFile int n_allocated_sections; }; +/** + * Parser for service files. + */ typedef struct { - DBusString data; + DBusString data; /**< The data from the file */ - BusDesktopFile *desktop_file; - int current_section; + BusDesktopFile *desktop_file; /**< The resulting object */ + int current_section; /**< The current section being parsed */ - int pos, len; - int line_num; + int pos; /**< Current position */ + int len; /**< Length */ + int line_num; /**< Current line number */ } BusDesktopFileParser; diff --git a/bus/services.c b/bus/services.c index 5148f1f1..84cabe21 100644 --- a/bus/services.c +++ b/bus/services.c @@ -417,10 +417,14 @@ bus_service_relink (BusService *service, bus_service_ref (service); } +/** + * Data used to represent an ownership cancellation in + * a bus transaction. + */ typedef struct { - DBusConnection *connection; - BusService *service; + DBusConnection *connection; /**< the connection */ + BusService *service; /**< service to cancel ownership of */ } OwnershipCancelData; static void 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 */ diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index 12468abb..b867d178 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -24,6 +24,8 @@ #include "dbus-gidl.h" +#ifndef DOXYGEN_SHOULD_SKIP_THIS + struct NodeInfo { int refcount; @@ -402,3 +404,5 @@ _dbus_gidl_test (void) } #endif /* DBUS_BUILD_TESTS */ + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 6e4e207a..7a667240 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -24,6 +24,8 @@ #ifndef DBUS_GLIB_IDL_H #define DBUS_GLIB_IDL_H +#ifndef DOXYGEN_SHOULD_SKIP_THIS + #include #include @@ -90,3 +92,5 @@ ArgDirection arg_info_get_direction (ArgInfo *info); G_END_DECLS #endif /* DBUS_GLIB_IDL_H */ + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 3a87dec2..4015dd99 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -39,19 +39,28 @@ void dbus_server_setup_with_g_main (DBusServer *server, typedef struct DBusGObjectInfo DBusGObjectInfo; typedef struct DBusGMethodInfo DBusGMethodInfo; +/** + * Object typically generated by dbus-glib-tool that + * stores a mapping from introspection data to a + * function pointer for a C method to be invoked. + */ struct DBusGMethodInfo { - GCallback function; - DBusHandleMessageFunction marshaller; - int data_offset; + GCallback function; /**< C method to invoke */ + DBusHandleMessageFunction marshaller; /**< Marshaller to go DBusMessage to C method */ + int data_offset; /**< Offset into the introspection data */ }; +/** + * Introspection data for a GObject, normally autogenerated by + * a tool such as dbus-glib-tool. + */ struct DBusGObjectInfo { - const DBusGMethodInfo *infos; - const unsigned char *data; - void *dbus_internal_padding1; - void *dbus_internal_padding2; + const DBusGMethodInfo *infos; /**< Array of method pointers */ + const unsigned char *data; /**< Introspection data */ + void *dbus_internal_padding1; /**< Reserved for expansion */ + void *dbus_internal_padding2; /**< Reserved for expansion */ }; void dbus_gobject_class_install_info (GObjectClass *object_class, diff --git a/glib/dbus-gloader-expat.c b/glib/dbus-gloader-expat.c index 050d3532..149e7117 100644 --- a/glib/dbus-gloader-expat.c +++ b/glib/dbus-gloader-expat.c @@ -43,13 +43,16 @@ static XML_Memory_Handling_Suite memsuite = g_free }; +/** + * Context for Expat parser for introspection data. + */ typedef struct { - Parser *parser; - const char *filename; - GString *content; - GError **error; - gboolean failed; + Parser *parser; /**< The parser for the introspection data */ + const char *filename; /**< The filename being loaded */ + GString *content; /**< The content of the current element */ + GError **error; /**< Error return location */ + gboolean failed; /**< True if parse has failed */ } ExpatParseContext; static dbus_bool_t diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index 36c6c6b4..c33f47e8 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -49,6 +49,9 @@ */ typedef struct DBusGSource DBusGSource; +/** + * A GSource subclass for a DBusConnection. + */ struct DBusGSource { GSource source; /**< the parent GSource */ diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c index c2b54d31..f7264b5e 100644 --- a/glib/dbus-gparser.c +++ b/glib/dbus-gparser.c @@ -28,6 +28,8 @@ #define _(x) gettext ((x)) #define N_(x) x +#ifndef DOXYGEN_SHOULD_SKIP_THIS + #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0) typedef struct @@ -656,3 +658,5 @@ parser_get_nodes (Parser *parser) { return parser->result; } + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 01a6b4b9..8951707b 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -28,17 +28,22 @@ * @{ */ +/** + * Internals of DBusGProxy + */ struct DBusGProxy { - GStaticMutex lock; - int refcount; - DBusConnection *connection; - char *service; - char *interface; - char *path; + GStaticMutex lock; /**< Thread lock */ + int refcount; /**< Reference count */ + DBusConnection *connection; /**< Connection to communicate over */ + char *service; /**< Service messages go to or NULL */ + char *interface; /**< Interface messages go to or NULL */ + char *path; /**< Path messages go to or NULL */ }; +/** Lock the DBusGProxy */ #define LOCK_PROXY(proxy) (g_static_mutex_lock (&(proxy)->lock)) +/** Unlock the DBusGProxy */ #define UNLOCK_PROXY(proxy) (g_static_mutex_unlock (&(proxy)->lock)) static DBusGProxy* -- cgit v1.2.1 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 --- ChangeLog | 66 ++++++++++++ Makefile.am | 2 +- configure.in | 30 ++++++ 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 + doc/TODO | 4 + glib/Makefile.am | 29 ++++-- glib/dbus-gidl.c | 226 ++++++++++++++++++++++++++++++---------- glib/dbus-gidl.h | 26 ++++- glib/dbus-glib.h | 71 +++++++++++-- glib/dbus-gloader-expat.c | 19 ++-- glib/dbus-gmain.c | 41 ++++++++ glib/dbus-gobject.c | 89 ++++++---------- glib/dbus-gparser.c | 8 ++ glib/dbus-gparser.h | 10 +- glib/dbus-gproxy.c | 101 +++++++++++++++--- glib/dbus-gtest.c | 4 + glib/dbus-gtest.h | 1 + glib/dbus-gthread.c | 2 +- test/Makefile.am | 2 +- test/glib/test-profile.c | 2 +- test/glib/test-thread-client.c | 2 +- test/glib/test-thread-server.c | 2 +- tools/Makefile.am | 18 +++- 31 files changed, 944 insertions(+), 201 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4dba23f..caa4a754 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,69 @@ +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 + 2003-09-07 Havoc Pennington * Make Doxygen contented. diff --git a/Makefile.am b/Makefile.am index 7384af0d..5bb5ae6a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ if DBUS_USE_MCS endif -SUBDIRS=dbus bus test doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) tools +SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) test tools pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = dbus-1.pc $(GLIB_PC) diff --git a/configure.in b/configure.in index c403fd8c..e81a8d6a 100644 --- a/configure.in +++ b/configure.in @@ -24,6 +24,7 @@ AC_HEADER_STDC AC_ARG_ENABLE(qt, [ --enable-qt enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto) AC_ARG_ENABLE(glib, [ --enable-glib enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto) +AC_ARG_ENABLE(gtk, [ --enable-gtk enable GTK-requiring executables],enable_gtk=$enableval,enable_gtk=auto) AC_ARG_ENABLE(tests, [ --enable-tests enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE) AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no) AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE) @@ -577,6 +578,34 @@ DBUS_GLIB_TOOL_LIBS=$XML_LIBS AC_SUBST(DBUS_GLIB_TOOL_CFLAGS) AC_SUBST(DBUS_GLIB_TOOL_LIBS) +# GTK detection +if test x$have_glib = xno ; then + AC_MSG_WARN([Can't use GTK+ since GLib not enabled]) + have_gtk=no +else + PKG_CHECK_MODULES(DBUS_GTK, gtk+-2.0, have_gtk=yes, have_gtk=no) +fi + +if test x$have_gtk = xno ; then + AC_MSG_WARN([GTK+ development libraries not found]) +fi + +if test x$enable_gtk = xyes; then + if test x$have_gtk = xno; then + AC_MSG_ERROR([GTK+ explicitly required, and GTK+ development libraries not found]) + fi +fi + +if test x$enable_gtk = xno; then + have_gtk=no; +fi + +AM_CONDITIONAL(HAVE_GTK, test x$have_gtk = xyes) + +dnl Gtk flags +AC_SUBST(DBUS_GTK_CFLAGS) +AC_SUBST(DBUS_GTK_LIBS) + # Qt detection have_qt=no AC_MSG_CHECKING([for qglobal.h]) @@ -885,6 +914,7 @@ echo " Building checks: ${enable_checks} Building Qt bindings: ${have_qt} Building GLib bindings: ${have_glib} + Building GTK+ tools: ${have_gtk} Building X11 code: ${enable_x11} Building documentation: ${enable_docs} Using XML parser: ${with_xml} 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), diff --git a/doc/TODO b/doc/TODO index 6b308d39..5c2b149c 100644 --- a/doc/TODO +++ b/doc/TODO @@ -82,3 +82,7 @@ - Nuke the org.freedesktop.Broadcast service; instead, just broadcast messages of type signal + + - I don't want to introduce DBusObject, but refcounting and object + data could still be factored out into an internal "base class" + perhaps. diff --git a/glib/Makefile.am b/glib/Makefile.am index 65d71cfd..a45aa593 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -5,8 +5,7 @@ dbusincludedir=$(includedir)/dbus-1.0/dbus lib_LTLIBRARIES=libdbus-glib-1.la dbusinclude_HEADERS= \ - dbus-glib.h \ - dbus-gproxy.h + dbus-glib.h libdbus_glib_1_la_SOURCES = \ dbus-gmain.c \ @@ -14,23 +13,36 @@ libdbus_glib_1_la_SOURCES = \ dbus-gproxy.c \ dbus-gtest.c \ dbus-gtest.h \ - dbus-gthread.c + dbus-gthread.c \ + dbus-gutils.c \ + dbus-gutils.h libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la +## don't export symbols that start with "_" (we use this +## convention for internal symbols) +libdbus_glib_1_la_LDFLAGS= -export-symbols-regex "^[^_].*" -bin_PROGRAMS=dbus-glib-tool +# convenience lib used here and by dbus-viewer +noinst_LTLIBRARIES=libdbus-gtool.la -dbus_glib_tool_SOURCES = \ +libdbus_gtool_la_SOURCES = \ dbus-gidl.c \ dbus-gidl.h \ - dbus-glib-tool.c \ dbus-gloader-expat.c \ dbus-gparser.c \ dbus-gparser.h \ - dbus-gtool-test.h + dbus-gutils.c \ + dbus-gutils.h +libdbus_gtool_la_LIBADD = libdbus-glib-1.la -dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-glib-1.la $(top_builddir)/dbus/libdbus-1.la +bin_PROGRAMS=dbus-glib-tool + +dbus_glib_tool_SOURCES = \ + dbus-glib-tool.c \ + dbus-gtool-test.h + +dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-gtool.la if DBUS_BUILD_TESTS @@ -54,3 +66,4 @@ else TESTS= endif + diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index b867d178..596b43ca 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -26,43 +26,131 @@ #ifndef DOXYGEN_SHOULD_SKIP_THIS -struct NodeInfo +struct BaseInfo { - int refcount; + unsigned int refcount : 28; + unsigned int type : 4; char *name; +}; + +struct NodeInfo +{ + BaseInfo base; GSList *interfaces; + GSList *nodes; }; struct InterfaceInfo { - int refcount; - char *name; + BaseInfo base; + /* Since we have BaseInfo now these could be one list */ GSList *methods; GSList *signals; }; struct MethodInfo { - int refcount; + BaseInfo base; GSList *args; - char *name; }; struct SignalInfo { - int refcount; + BaseInfo base; GSList *args; - char *name; }; struct ArgInfo { - int refcount; - char *name; + BaseInfo base; int type; ArgDirection direction; }; +void +base_info_ref (BaseInfo *info) +{ + g_return_if_fail (info != NULL); + g_return_if_fail (info->refcount > 0); + + info->refcount += 1; +} + +static void +base_info_free (void *ptr) +{ + BaseInfo *info; + + info = ptr; + + g_free (info->name); + g_free (info); +} + +void +base_info_unref (BaseInfo *info) +{ + g_return_if_fail (info != NULL); + g_return_if_fail (info->refcount > 0); + + /* This is sort of bizarre, BaseInfo was tacked on later */ + + switch (info->type) + { + case INFO_TYPE_NODE: + node_info_unref ((NodeInfo*) info); + break; + case INFO_TYPE_INTERFACE: + interface_info_unref ((InterfaceInfo*) info); + break; + case INFO_TYPE_SIGNAL: + signal_info_unref ((SignalInfo*) info); + break; + case INFO_TYPE_METHOD: + method_info_unref ((MethodInfo*) info); + break; + case INFO_TYPE_ARG: + arg_info_unref ((ArgInfo*) info); + break; + } +} + +InfoType +base_info_get_type (BaseInfo *info) +{ + return info->type; +} + +const char* +base_info_get_name (BaseInfo *info) +{ + return info->name; +} + +void +base_info_set_name (BaseInfo *info, + const char *name) +{ + char *old; + + old = info->name; + info->name = g_strdup (name); + g_free (old); +} + +GType +base_info_get_gtype (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("BaseInfo", + (GBoxedCopyFunc) base_info_ref, + (GBoxedFreeFunc) base_info_unref); + + return our_type; +} + static void free_interface_list (GSList **interfaces_p) { @@ -77,6 +165,20 @@ free_interface_list (GSList **interfaces_p) *interfaces_p = NULL; } +static void +free_node_list (GSList **nodes_p) +{ + GSList *tmp; + tmp = *nodes_p; + while (tmp != NULL) + { + node_info_unref (tmp->data); + tmp = tmp->next; + } + g_slist_free (*nodes_p); + *nodes_p = NULL; +} + static void free_method_list (GSList **methods_p) { @@ -113,34 +215,35 @@ node_info_new (const char *name) /* name can be NULL */ info = g_new0 (NodeInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_NODE; + return info; } void node_info_ref (NodeInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void node_info_unref (NodeInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_interface_list (&info->interfaces); - g_free (info->name); - g_free (info); + free_node_list (&info->nodes); + base_info_free (info); } } const char* node_info_get_name (NodeInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -157,6 +260,19 @@ node_info_add_interface (NodeInfo *info, info->interfaces = g_slist_append (info->interfaces, interface); } +GSList* +node_info_get_nodes (NodeInfo *info) +{ + return info->nodes; +} + +void +node_info_add_node (NodeInfo *info, + NodeInfo *node) +{ + node_info_ref (node); + info->nodes = g_slist_append (info->nodes, node); +} InterfaceInfo* interface_info_new (const char *name) @@ -164,35 +280,35 @@ interface_info_new (const char *name) InterfaceInfo *info; info = g_new0 (InterfaceInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_INTERFACE; + return info; } void interface_info_ref (InterfaceInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void interface_info_unref (InterfaceInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_method_list (&info->methods); free_signal_list (&info->signals); - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* interface_info_get_name (InterfaceInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -243,34 +359,34 @@ method_info_new (const char *name) MethodInfo *info; info = g_new0 (MethodInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_METHOD; + return info; } void method_info_ref (MethodInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void method_info_unref (MethodInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_arg_list (&info->args); - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* method_info_get_name (MethodInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -293,34 +409,34 @@ signal_info_new (const char *name) SignalInfo *info; info = g_new0 (SignalInfo, 1); - info->refcount = 1; - info->name = g_strdup (name); - + info->base.refcount = 1; + info->base.name = g_strdup (name); + info->base.type = INFO_TYPE_SIGNAL; + return info; } void signal_info_ref (SignalInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void signal_info_unref (SignalInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { free_arg_list (&info->args); - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* signal_info_get_name (SignalInfo *info) { - return info->name; + return info->base.name; } GSList* @@ -345,10 +461,11 @@ arg_info_new (const char *name, ArgInfo *info; info = g_new0 (ArgInfo, 1); - info->refcount = 1; - + info->base.refcount = 1; + info->base.type = INFO_TYPE_ARG; + /* name can be NULL */ - info->name = g_strdup (name); + info->base.name = g_strdup (name); info->direction = direction; info->type = type; @@ -358,23 +475,22 @@ arg_info_new (const char *name, void arg_info_ref (ArgInfo *info) { - info->refcount += 1; + info->base.refcount += 1; } void arg_info_unref (ArgInfo *info) { - info->refcount -= 1; - if (info->refcount == 0) + info->base.refcount -= 1; + if (info->base.refcount == 0) { - g_free (info->name); - g_free (info); + base_info_free (info); } } const char* arg_info_get_name (ArgInfo *info) { - return info->name; + return info->base.name; } int diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 7a667240..f95abfbd 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -27,10 +27,11 @@ #ifndef DOXYGEN_SHOULD_SKIP_THIS #include -#include +#include G_BEGIN_DECLS +typedef struct BaseInfo BaseInfo; typedef struct NodeInfo NodeInfo; typedef struct InterfaceInfo InterfaceInfo; typedef struct MethodInfo MethodInfo; @@ -43,13 +44,36 @@ typedef enum ARG_OUT } ArgDirection; +typedef enum +{ + INFO_TYPE_NODE, + INFO_TYPE_INTERFACE, + INFO_TYPE_METHOD, + INFO_TYPE_SIGNAL, + INFO_TYPE_ARG + +} InfoType; + +void base_info_ref (BaseInfo *info); +void base_info_unref (BaseInfo *info); +InfoType base_info_get_type (BaseInfo *info); +const char* base_info_get_name (BaseInfo *info); +void base_info_set_name (BaseInfo *info, + const char *name); +GType base_info_get_gtype (void); +#define BASE_INFO_TYPE (base_info_get_gtype ()) + + NodeInfo* node_info_new (const char *name); void node_info_ref (NodeInfo *info); void node_info_unref (NodeInfo *info); const char* node_info_get_name (NodeInfo *info); GSList* node_info_get_interfaces (NodeInfo *info); +GSList* node_info_get_nodes (NodeInfo *info); void node_info_add_interface (NodeInfo *info, InterfaceInfo *interface); +void node_info_add_node (NodeInfo *info, + NodeInfo *child); InterfaceInfo* interface_info_new (const char *name); void interface_info_ref (InterfaceInfo *info); diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 4015dd99..63d34485 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -2,6 +2,7 @@ /* dbus-glib.h GLib integration * * Copyright (C) 2002, 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. * * Licensed under the Academic Free License version 1.2 * @@ -30,7 +31,22 @@ G_BEGIN_DECLS #define DBUS_INSIDE_DBUS_GLIB_H 1 -void dbus_gthread_init (void); +GQuark dbus_g_error_quark (void); +#define DBUS_GERROR dbus_g_error_quark () + +typedef enum +{ + /* FIXME map all the DBUS_ERROR to DBUS_GERROR, should + * probably be automated in some way, perhaps + * via lame perl script + */ + DBUS_GERROR_FAILED +} DBusGError; + +void dbus_set_g_error (GError **gerror, + DBusError *derror); + +void dbus_g_thread_init (void); void dbus_connection_setup_with_g_main (DBusConnection *connection, GMainContext *context); void dbus_server_setup_with_g_main (DBusServer *server, @@ -63,14 +79,57 @@ struct DBusGObjectInfo void *dbus_internal_padding2; /**< Reserved for expansion */ }; -void dbus_gobject_class_install_info (GObjectClass *object_class, - const DBusGObjectInfo *info); -void dbus_connection_register_gobject (DBusConnection *connection, - const char *at_path, - GObject *object); +void dbus_g_object_class_install_info (GObjectClass *object_class, + const DBusGObjectInfo *info); +void dbus_connection_register_g_object (DBusConnection *connection, + const char *at_path, + GObject *object); + + +typedef struct DBusGProxy DBusGProxy; + +DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, + const char *service_name, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, + const char *service_name, + const char *interface_name, + GError **error); +DBusGProxy* dbus_gproxy_new_for_object_path (DBusConnection *connection, + const char *path, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, + const char *interface_name); +void dbus_gproxy_ref (DBusGProxy *proxy); +void dbus_gproxy_unref (DBusGProxy *proxy); +gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *signal_name, + GCallback callback, + void *data, + GFreeFunc free_data_func, + GError **error); +DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); +gboolean dbus_gproxy_end_call (DBusGProxy *proxy, + DBusPendingCall *pending, + GError **error, + int first_arg_type, + ...); +void dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...); +void dbus_gproxy_send (DBusGProxy *proxy, + DBusMessage *message, + dbus_uint32_t *client_serial); #undef DBUS_INSIDE_DBUS_GLIB_H G_END_DECLS #endif /* DBUS_GLIB_H */ + + + diff --git a/glib/dbus-gloader-expat.c b/glib/dbus-gloader-expat.c index 149e7117..01587d21 100644 --- a/glib/dbus-gloader-expat.c +++ b/glib/dbus-gloader-expat.c @@ -163,31 +163,32 @@ expat_CharacterDataHandler (void *userData, s, len); } -Parser* +NodeInfo* description_load_from_file (const char *filename, GError **error) { char *contents; gsize len; - Parser *parser; + NodeInfo *nodes; contents = NULL; if (!g_file_get_contents (filename, &contents, &len, error)) return NULL; - parser = description_load_from_string (contents, len, error); + nodes = description_load_from_string (contents, len, error); g_free (contents); - return parser; + return nodes; } -Parser* +NodeInfo* description_load_from_string (const char *str, int len, GError **error) { XML_Parser expat; ExpatParseContext context; + NodeInfo *nodes; g_return_val_if_fail (error == NULL || *error == NULL, NULL); @@ -242,8 +243,11 @@ description_load_from_string (const char *str, XML_ParserFree (expat); g_string_free (context.content, TRUE); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - return context.parser; + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + nodes = parser_get_nodes (context.parser); + node_info_ref (nodes); + parser_unref (context.parser); + return nodes; failed: g_return_val_if_fail (error == NULL || *error != NULL, NULL); @@ -255,3 +259,4 @@ description_load_from_string (const char *str, parser_unref (context.parser); return NULL; } + diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index c33f47e8..2e5604dc 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -25,6 +25,10 @@ #include "dbus-glib.h" #include "dbus-gtest.h" +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x + /** * @defgroup DBusGLib GLib bindings * @ingroup DBus @@ -494,6 +498,43 @@ dbus_server_setup_with_g_main (DBusServer *server, g_error ("Not enough memory to set up DBusServer for use with GLib"); } +/** + * The implementation of DBUS_GERROR error domain. See documentation + * for GError in GLib reference manual. + * + * @returns the error domain quark for use with GError + */ +GQuark +dbus_g_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("g-exec-error-quark"); + return quark; +} + + +/** + * Set a GError return location from a DBusError. + * + * @todo expand the DBUS_GERROR enum and take advantage of it here + * + * @param gerror location to store a GError, or #NULL + * @param derror the DBusError + */ +void +dbus_set_g_error (GError **gerror, + DBusError *derror) +{ + g_return_if_fail (derror != NULL); + g_return_if_fail (dbus_error_is_set (derror)); + + g_set_error (gerror, DBUS_GERROR, + DBUS_GERROR_FAILED, + _("D-BUS error %s: %s"), + derror->name, derror->message); +} + /** @} */ /* end of public API */ #ifdef DBUS_BUILD_TESTS diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index b0f6c139..6e65770f 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -24,6 +24,7 @@ #include #include "dbus-glib.h" #include "dbus-gtest.h" +#include "dbus-gutils.h" #include /** @@ -102,6 +103,7 @@ gobject_unregister_function (DBusConnection *connection, object = G_OBJECT (user_data); + /* FIXME */ } @@ -187,6 +189,15 @@ handle_introspect (DBusConnection *connection, unsigned int i; GType last_type; DBusMessage *ret; + char **path; + char **children; + + if (!dbus_message_get_path_decomposed (message, &path)) + g_error ("Out of memory"); + + if (!dbus_connection_list_registered (connection, (const char**) path, + &children)) + g_error ("Out of memory"); xml = g_string_new (NULL); @@ -268,13 +279,23 @@ handle_introspect (DBusConnection *connection, g_free (specs); + /* Append child nodes */ + + i = 0; + while (children[i]) + { + g_string_append_printf (xml, " \n", + children[i]); + ++i; + } + /* Close the XML, and send it to the requesting app */ g_string_append (xml, "\n"); ret = dbus_message_new_method_return (message); if (ret == NULL) - g_error ("out of memory"); + g_error ("Out of memory"); dbus_message_append_args (message, DBUS_TYPE_STRING, xml->str, @@ -285,6 +306,9 @@ handle_introspect (DBusConnection *connection, g_string_free (xml, TRUE); + dbus_free_string_array (path); + dbus_free_string_array (children); + return DBUS_HANDLER_RESULT_HANDLED; } @@ -642,15 +666,15 @@ static DBusObjectPathVTable gobject_dbus_vtable = { * class_init() for the object class. * * Once introspection information has been installed, instances of the - * object registered with dbus_connection_register_gobject() can have + * object registered with dbus_connection_register_g_object() can have * their methods invoked remotely. * * @param object_class class struct of the object * @param info introspection data generated by dbus-glib-tool */ void -dbus_gobject_class_install_info (GObjectClass *object_class, - const DBusGObjectInfo *info) +dbus_g_object_class_install_info (GObjectClass *object_class, + const DBusGObjectInfo *info) { g_return_if_fail (G_IS_OBJECT_CLASS (object_class)); @@ -666,55 +690,6 @@ dbus_gobject_class_install_info (GObjectClass *object_class, g_static_mutex_unlock (&info_hash_mutex); } -static char** -split_path (const char *path) -{ - int len; - char **split; - int n_components; - int i, j, comp; - - len = strlen (path); - - n_components = 0; - i = 0; - while (i < len) - { - if (path[i] == '/') - n_components += 1; - ++i; - } - - split = g_new0 (char*, n_components + 1); - - comp = 0; - i = 0; - while (i < len) - { - if (path[i] == '/') - ++i; - j = i; - - while (j < len && path[j] != '/') - ++j; - - /* Now [i, j) is the path component */ - g_assert (i < j); - g_assert (path[i] != '/'); - g_assert (j == len || path[j] == '/'); - - split[comp] = g_strndup (&path[i], j - i + 1); - - split[comp][j-i] = '\0'; - - ++comp; - i = j; - } - g_assert (i == len); - - return split; -} - /** * Registers a GObject at the given path. Properties, methods, and signals * of the object can then be accessed remotely. Methods are only available @@ -729,9 +704,9 @@ split_path (const char *path) * @param object the object */ void -dbus_connection_register_gobject (DBusConnection *connection, - const char *at_path, - GObject *object) +dbus_connection_register_g_object (DBusConnection *connection, + const char *at_path, + GObject *object) { char **split; @@ -739,7 +714,7 @@ dbus_connection_register_gobject (DBusConnection *connection, g_return_if_fail (at_path != NULL); g_return_if_fail (G_IS_OBJECT (object)); - split = split_path (at_path); + split = _dbus_gutils_split_path (at_path); if (!dbus_connection_register_object_path (connection, (const char**) split, diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c index f7264b5e..16d17f3d 100644 --- a/glib/dbus-gparser.c +++ b/glib/dbus-gparser.c @@ -262,7 +262,15 @@ parse_node (Parser *parser, return FALSE; } + node = node_info_new (name); + + if (parser->node_stack != NULL) + { + node_info_add_node (parser->node_stack->data, + node); + } + parser->node_stack = g_slist_prepend (parser->node_stack, node); diff --git a/glib/dbus-gparser.h b/glib/dbus-gparser.h index 3e87165b..cc58e5e0 100644 --- a/glib/dbus-gparser.h +++ b/glib/dbus-gparser.h @@ -52,11 +52,11 @@ gboolean parser_content (Parser *parser, gboolean parser_finished (Parser *parser, GError **error); -Parser* description_load_from_file (const char *filename, - GError **error); -Parser* description_load_from_string (const char *str, - int len, - GError **error); +NodeInfo* description_load_from_file (const char *filename, + GError **error); +NodeInfo* description_load_from_string (const char *str, + int len, + GError **error); NodeInfo* parser_get_nodes (Parser *parser); diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 8951707b..59d86a31 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -20,7 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#include "dbus-gproxy.h" +#include "dbus-glib.h" /** * @addtogroup DBusGLibInternals @@ -165,23 +165,59 @@ dbus_gproxy_unref (DBusGProxy *proxy) * To collect the results of the call (which may be an error, * or a reply), use dbus_gproxy_end_call(). * + * @todo this particular function shouldn't die on out of memory, + * since you should be able to do a call with large arguments. + * * @param proxy a proxy for a remote interface * @param method the name of the method to invoke * @param first_arg_type type of the first argument * * @returns opaque pending call object - * - */ + * */ DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, const char *method, int first_arg_type, ...) { + DBusPendingCall *pending; + DBusMessage *message; + va_list args; + g_return_val_if_fail (proxy != NULL, NULL); LOCK_PROXY (proxy); + message = dbus_message_new_method_call (proxy->service, + proxy->interface, + proxy->path, + method); + if (message == NULL) + goto oom; + + va_start (args, first_arg_type); + if (!dbus_message_append_args_valist (message, first_arg_type, + args)) + goto oom; + va_end (args); + + if (!dbus_connection_send_with_reply (proxy->connection, + message, + &pending, + -1)) + goto oom; + UNLOCK_PROXY (proxy); + + return pending; + + oom: + /* FIXME we should create a pending call that's + * immediately completed with an error status without + * ever going on the wire. + */ + + g_error ("Out of memory"); + return NULL; } /** @@ -189,7 +225,9 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, * initiated with dbus_gproxy_end_call(). This function will block if * the results haven't yet been received; use * dbus_pending_call_set_notify() to be notified asynchronously that a - * pending call has been completed. + * pending call has been completed. Use + * dbus_pending_call_get_completed() to check whether a call has been + * completed. If it's completed, it will not block. * * If the call results in an error, the error is set as normal for * GError and the function returns #FALSE. @@ -198,12 +236,15 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, * method are stored in the provided varargs list. * The list should be terminated with DBUS_TYPE_INVALID. * + * This function doesn't affect the reference count of the + * #DBusPendingCall, the caller of dbus_gproxy_begin_call() still owns + * a reference. + * * @param proxy a proxy for a remote interface * @param pending the pending call from dbus_gproxy_begin_call() * @param error return location for an error * @param first_arg_type type of first "out" argument - * @returns #FALSE if an error is set - */ + * @returns #FALSE if an error is set */ gboolean dbus_gproxy_end_call (DBusGProxy *proxy, DBusPendingCall *pending, @@ -211,10 +252,37 @@ dbus_gproxy_end_call (DBusGProxy *proxy, int first_arg_type, ...) { + DBusMessage *message; + va_list args; + DBusError derror; + g_return_val_if_fail (proxy != NULL, FALSE); + g_return_val_if_fail (pending != NULL, FALSE); + LOCK_PROXY (proxy); + dbus_pending_call_block (pending); + message = dbus_pending_call_get_reply (pending); + + g_assert (message != NULL); + + dbus_error_init (&derror); + va_start (args, first_arg_type); + if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args)) + { + va_end (args); + goto error; + } + va_end (args); + UNLOCK_PROXY (proxy); + + return TRUE; + + error: + dbus_set_g_error (error, &derror); + dbus_error_free (&derror); + return FALSE; } /** @@ -224,18 +292,17 @@ dbus_gproxy_end_call (DBusGProxy *proxy, * dbus_connection_flush(). * * The message is modified to be addressed to the target interface. - * That is, a destination service field or whatever is needed - * will be added to the message. + * That is, a destination service field or whatever is needed will be + * added to the message. The basic point of this function is to add + * the necessary header fields, otherwise it's equivalent to + * dbus_connection_send(). * * This function adds a reference to the message, so the caller * still owns its original reference. - * - * @todo fix for sending to interfaces and object IDs * * @param proxy a proxy for a remote interface * @param message the message to address and send - * @param client_serial return location for message's serial, or #NULL - */ + * @param client_serial return location for message's serial, or #NULL */ void dbus_gproxy_send (DBusGProxy *proxy, DBusMessage *message, @@ -247,17 +314,19 @@ dbus_gproxy_send (DBusGProxy *proxy, if (proxy->service) { if (!dbus_message_set_destination (message, proxy->service)) - g_error ("Out of memory\n"); + g_error ("Out of memory"); } if (proxy->interface) { - /* FIXME */ + if (!dbus_message_set_interface (message, proxy->interface)) + g_error ("Out of memory"); } if (proxy->path) { - /* FIXME */ + if (!dbus_message_set_path (message, proxy->path)) + g_error ("Out of memory"); } - + if (!dbus_connection_send (proxy->connection, message, client_serial)) g_error ("Out of memory\n"); diff --git a/glib/dbus-gtest.c b/glib/dbus-gtest.c index b853d3ed..48cd13f0 100644 --- a/glib/dbus-gtest.c +++ b/glib/dbus-gtest.c @@ -56,6 +56,10 @@ dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir) else printf ("No test data!\n"); + printf ("%s: running utils tests\n", "dbus-glib-test"); + if (!_dbus_gutils_test (test_data_dir)) + die ("gutils"); + printf ("%s: running mainloop integration tests\n", "dbus-glib-test"); if (!_dbus_gmain_test (test_data_dir)) die ("gmain"); diff --git a/glib/dbus-gtest.h b/glib/dbus-gtest.h index 6a33bdae..1174eb0a 100644 --- a/glib/dbus-gtest.h +++ b/glib/dbus-gtest.h @@ -28,6 +28,7 @@ dbus_bool_t _dbus_gmain_test (const char *test_data_dir); dbus_bool_t _dbus_gobject_test (const char *test_data_dir); +dbus_bool_t _dbus_gutils_test (const char *test_data_dir); void dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir); diff --git a/glib/dbus-gthread.c b/glib/dbus-gthread.c index 71a3c1f5..eb3e5572 100644 --- a/glib/dbus-gthread.c +++ b/glib/dbus-gthread.c @@ -165,7 +165,7 @@ dbus_gcondvar_wake_all (DBusCondVar *cond) * other function in the D-BUS API. */ void -dbus_gthread_init (void) +dbus_g_thread_init (void) { if (!g_thread_supported ()) g_error ("g_thread_init() must be called before dbus_threads_init()"); diff --git a/test/Makefile.am b/test/Makefile.am index ab04496e..84089517 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -89,7 +89,7 @@ all-local: for D in $(TESTDIRS); do \ test -d $(top_builddir)/test/$$D || mkdir $(top_builddir)/test/$$D || exit 1 ; \ done ; \ - if test $(srcdir) != . ; then \ + if ! (test $(srcdir) = . || test $(srcdir) -ef .) ; then \ FILES=`(cd $(srcdir) && $(FIND_TESTS))` ; \ for F in $$FILES; do \ SRC=$(srcdir)/$$F ; \ diff --git a/test/glib/test-profile.c b/test/glib/test-profile.c index 6d9d8e7f..23547a1f 100644 --- a/test/glib/test-profile.c +++ b/test/glib/test-profile.c @@ -185,7 +185,7 @@ main (int argc, char *argv[]) int i; g_thread_init (NULL); - dbus_gthread_init (); + dbus_g_thread_init (); dbus_error_init (&error); server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, diff --git a/test/glib/test-thread-client.c b/test/glib/test-thread-client.c index d51d4e6a..122c839a 100644 --- a/test/glib/test-thread-client.c +++ b/test/glib/test-thread-client.c @@ -66,7 +66,7 @@ main (int argc, char *argv[]) int i; g_thread_init (NULL); - dbus_gthread_init (); + dbus_g_thread_init (); if(argc < 2) { diff --git a/test/glib/test-thread-server.c b/test/glib/test-thread-server.c index 8898ca7f..dd560328 100644 --- a/test/glib/test-thread-server.c +++ b/test/glib/test-thread-server.c @@ -178,7 +178,7 @@ main (int argc, char *argv[]) DBusError error; g_thread_init (NULL); - dbus_gthread_init (); + dbus_g_thread_init (); if (argc < 2) { diff --git a/tools/Makefile.am b/tools/Makefile.am index 80957854..a6a38a97 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) $(DBUS_GTK_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" if HAVE_GLIB GLIB_TOOLS=dbus-monitor @@ -6,7 +6,13 @@ else GLIB_TOOLS= endif -bin_PROGRAMS=dbus-send $(GLIB_TOOLS) dbus-launch dbus-cleanup-sockets +if HAVE_GTK +GTK_TOOLS=dbus-viewer +else +GTK_TOOLS= +endif + +bin_PROGRAMS=dbus-send $(GLIB_TOOLS) dbus-launch dbus-cleanup-sockets $(GTK_TOOLS) dbus_send_SOURCES= \ dbus-print-message.c \ @@ -24,9 +30,17 @@ dbus_launch_SOURCES= \ dbus_cleanup_sockets_SOURCES= \ dbus-cleanup-sockets.c +dbus_viewer_SOURCES= \ + dbus-tree-view.c \ + dbus-tree-view.h \ + dbus-viewer.c + dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la dbus_monitor_LDADD= $(top_builddir)/glib/libdbus-glib-1.la dbus_launch_LDADD= $(DBUS_X_LIBS) +dbus_viewer_LDADD= $(top_builddir)/glib/libdbus-gtool.la $(DBUS_GTK_LIBS) man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 EXTRA_DIST = $(man_MANS) + + -- cgit v1.2.1 From fafc38bb45db8031fc6f252e86df86dc585fefc9 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 17 Sep 2003 13:56:29 +0000 Subject: must cvs add... --- glib/dbus-gutils.c | 96 +++++++++++++ glib/dbus-gutils.h | 40 ++++++ tools/dbus-tree-view.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/dbus-tree-view.h | 36 +++++ tools/dbus-viewer.c | 320 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 865 insertions(+) create mode 100644 glib/dbus-gutils.c create mode 100644 glib/dbus-gutils.h create mode 100644 tools/dbus-tree-view.c create mode 100644 tools/dbus-tree-view.h create mode 100644 tools/dbus-viewer.c diff --git a/glib/dbus-gutils.c b/glib/dbus-gutils.c new file mode 100644 index 00000000..e99286f8 --- /dev/null +++ b/glib/dbus-gutils.c @@ -0,0 +1,96 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gutils.c Utils shared between convenience lib and installed lib + * + * 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-gutils.h" +#include "dbus-gtest.h" +#include + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +char** +_dbus_gutils_split_path (const char *path) +{ + int len; + char **split; + int n_components; + int i, j, comp; + + len = strlen (path); + + n_components = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + n_components += 1; + ++i; + } + + split = g_new0 (char*, n_components + 1); + + comp = 0; + i = 0; + while (i < len) + { + if (path[i] == '/') + ++i; + j = i; + + while (j < len && path[j] != '/') + ++j; + + /* Now [i, j) is the path component */ + g_assert (i < j); + g_assert (path[i] != '/'); + g_assert (j == len || path[j] == '/'); + + split[comp] = g_strndup (&path[i], j - i + 1); + + split[comp][j-i] = '\0'; + + ++comp; + i = j; + } + g_assert (i == len); + + return split; +} + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGLibInternals + * Unit test for GLib utils internals + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gutils_test (const char *test_data_dir) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/glib/dbus-gutils.h b/glib/dbus-gutils.h new file mode 100644 index 00000000..af7cee45 --- /dev/null +++ b/glib/dbus-gutils.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gutils.h Utils shared between convenience lib and installed lib + * + * 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_GLIB_UTILS_H +#define DBUS_GLIB_UTILS_H + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include +#include + +G_BEGIN_DECLS + +char** _dbus_gutils_split_path (const char *path); + +G_END_DECLS + +#endif /* DBUS_GLIB_UTILS_H */ + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/tools/dbus-tree-view.c b/tools/dbus-tree-view.c new file mode 100644 index 00000000..863ad1e0 --- /dev/null +++ b/tools/dbus-tree-view.c @@ -0,0 +1,373 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-tree-view.c GtkTreeView for a D-BUS interface description + * + * 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 +#include "dbus-tree-view.h" + +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x + +enum +{ + MODEL_COLUMN_INFO, + + MODEL_COLUMN_LAST +}; + +enum +{ + VIEW_COLUMN_NAME, + + VIEW_COLUMN_LAST +}; + +/* We stuff the node tree into a GtkTreeStore, rather + * than bothering to write a custom model + */ +static GtkTreeModel* +model_new (void) +{ + GtkTreeModel *model; + GtkTreeStore *store; + + store = gtk_tree_store_new (MODEL_COLUMN_LAST, + G_TYPE_POINTER); + /* FIXME, BASE_INFO_TYPE doesn't work right (crashes), + * G_TYPE_POINTER has a memleak. BASE_INFO_TYPE problem maybe just a + * bad GTK build on my laptop. + */ + /* BASE_INFO_TYPE); */ + + model = GTK_TREE_MODEL (store); + + return model; +} + +static void set_info (GtkTreeModel *model, + GtkTreeIter *root, + BaseInfo *info); + +static void +append_child_list (GtkTreeModel *model, + GtkTreeIter *parent, + GSList *children) +{ + GSList *tmp; + GtkTreeStore *store; + + store = GTK_TREE_STORE (model); + + /* parent may be NULL for root */ + + tmp = children; + while (tmp != NULL) + { + GtkTreeIter iter; + + gtk_tree_store_append (store, &iter, parent); + + set_info (model, &iter, tmp->data); + + tmp = tmp->next; + } +} + +static void +set_info (GtkTreeModel *model, + GtkTreeIter *root, + BaseInfo *info) +{ + GtkTreeStore *store; + GtkTreeIter child; + + store = GTK_TREE_STORE (model); + + /* Remeber that root is NULL for "/" path */ + + /* Clear existing children */ + while (gtk_tree_model_iter_children (model, &child, root)) + gtk_tree_store_remove (store, &child); + + /* Set our new value; we simply discard NodeInfo for "/" at the + * moment. + */ + if (root != NULL) + { + base_info_ref (info); /* FIXME once boxed types are working */ + gtk_tree_store_set (store, root, + MODEL_COLUMN_INFO, info, + -1); + } + + /* Fill in new children */ + switch (base_info_get_type (info)) + { + case INFO_TYPE_NODE: + append_child_list (model, root, + node_info_get_interfaces ((NodeInfo*)info)); + append_child_list (model, root, + node_info_get_nodes ((NodeInfo*)info)); + break; + case INFO_TYPE_INTERFACE: + append_child_list (model, root, + interface_info_get_methods ((InterfaceInfo*)info)); + append_child_list (model, root, + interface_info_get_signals ((InterfaceInfo*)info)); + break; + case INFO_TYPE_METHOD: + append_child_list (model, root, + method_info_get_args ((MethodInfo*)info)); + break; + case INFO_TYPE_SIGNAL: + append_child_list (model, root, + signal_info_get_args ((SignalInfo*)info)); + break; + case INFO_TYPE_ARG: + /* no children */ + break; + } +} + +static void +ensure_tree_node (GtkTreeModel *model, + const char **path, + GtkTreeIter *iter) +{ + GtkTreeStore *store; + int i; + GtkTreeIter child; + GtkTreeIter *parent; + GtkTreeIter prev; + + store = GTK_TREE_STORE (model); + + /* The path[0] == NULL case for path "/" can't happen since no tree + * node is created for that + */ + g_assert (path[0] != NULL); + + parent = NULL; + + i = 0; + while (path[i] != NULL) + { + gboolean found; + + found = FALSE; + + if (gtk_tree_model_iter_children (model, &child, parent)) + { + /* Scan for the right path */ + do + { + BaseInfo *info; + + info = NULL; + gtk_tree_model_get (model, &child, + MODEL_COLUMN_INFO, &info, + -1); + + if (info != NULL && + base_info_get_type (info) == INFO_TYPE_NODE && + strcmp (base_info_get_name (info), path[i]) == 0) + { + /* Found it */ + found = TRUE; + break; + } + } + while (gtk_tree_model_iter_next (model, &child)); + } + + if (!found) + { + NodeInfo *node; + + node = node_info_new (path[i]); + + gtk_tree_store_append (store, &child, parent); + gtk_tree_store_set (store, &child, + MODEL_COLUMN_INFO, node, + -1); + } + + prev = child; + parent = &prev; + + ++i; + } + + g_assert (parent == &prev); + *iter = prev; +} + +static void +model_update (GtkTreeModel *model, + const char **path, + NodeInfo *node) +{ + GtkTreeStore *store; + + store = GTK_TREE_STORE (model); + + if (path[0] == NULL) + { + /* Setting '/' */ + + set_info (model, NULL, (BaseInfo*) node); + } + else + { + GtkTreeIter iter; + BaseInfo *old; + + /* Be sure we have the parent node */ + ensure_tree_node (model, path, &iter); + + /* Force the canonical relative path name on the node */ + old = NULL; + gtk_tree_model_get (model, &iter, + MODEL_COLUMN_INFO, &old, + -1); + base_info_set_name ((BaseInfo*) node, + base_info_get_name (old)); + + /* Fill in the new children */ + set_info (model, &iter, (BaseInfo*) node); + } +} + +static void +info_set_func_text (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + BaseInfo *info; + GString *str; + + info = NULL; + gtk_tree_model_get (model, iter, + MODEL_COLUMN_INFO, &info, + -1); + + if (info == NULL) + return; + + str = g_string_new (NULL); + + switch (base_info_get_type (info)) + { + case INFO_TYPE_NODE: + g_string_append (str, "path"); + break; + case INFO_TYPE_INTERFACE: + g_string_append (str, "interface"); + break; + case INFO_TYPE_METHOD: + g_string_append (str, "method"); + break; + case INFO_TYPE_SIGNAL: + g_string_append (str, "signal"); + break; + case INFO_TYPE_ARG: + g_string_append (str, "arg"); + break; + } + + g_string_append (str, " "); + g_string_append (str, base_info_get_name (info)); + + g_object_set (GTK_CELL_RENDERER (cell), + "markup", str->str, + NULL); + + g_string_free (str, TRUE); + + /* base_info_unref (info); */ +} + +GtkWidget* +dbus_tree_view_new (void) +{ + GtkWidget *treeview; + GtkCellRenderer *cell_renderer; + GtkTreeViewColumn *column; + + treeview = gtk_tree_view_new (); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Name")); + + cell_renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, + cell_renderer, + TRUE); + gtk_tree_view_column_set_cell_data_func (column, cell_renderer, + info_set_func_text, NULL, NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), + column); + + return treeview; +} + +void +dbus_tree_view_update (GtkTreeView *view, + const char **path, + NodeInfo *node) +{ + GtkTreeModel *model; + + g_return_if_fail (GTK_IS_TREE_VIEW (view)); + + model = gtk_tree_view_get_model (view); + + if (model == NULL) + { + model = model_new (); + model_update (model, path, node); + gtk_tree_view_set_model (view, model); + g_object_unref (G_OBJECT (model)); + } + else + { + model_update (model, path, node); + } +} + +void +dbus_tree_view_clear (GtkTreeView *view) +{ + GtkTreeModel *model; + + g_return_if_fail (GTK_IS_TREE_VIEW (view)); + + model = gtk_tree_view_get_model (view); + + if (model != NULL) + gtk_tree_store_clear (GTK_TREE_STORE (model)); +} + diff --git a/tools/dbus-tree-view.h b/tools/dbus-tree-view.h new file mode 100644 index 00000000..3377ac88 --- /dev/null +++ b/tools/dbus-tree-view.h @@ -0,0 +1,36 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-tree-view.h GtkTreeView for a D-BUS interface description + * + * 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_TREE_VIEW_H +#define DBUS_TREE_VIEW_H + +#include +#include +#include + +GtkWidget* dbus_tree_view_new (void); +void dbus_tree_view_update (GtkTreeView *view, + const char **path, + NodeInfo *info); +void dbus_tree_view_clear (GtkTreeView *view); + +#endif /* DBUS_TREE_VIEW_H */ diff --git a/tools/dbus-viewer.c b/tools/dbus-viewer.c new file mode 100644 index 00000000..561a65af --- /dev/null +++ b/tools/dbus-viewer.c @@ -0,0 +1,320 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-viewer.c Graphical D-BUS frontend utility + * + * 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 +#include +#include +#include +#include +#include "dbus-tree-view.h" +#include +#include + +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x + +typedef struct +{ + int refcount; + char *name; + +} ServiceData; + +static ServiceData* +service_data_new (const char *name) +{ + ServiceData *sd; + + sd = g_new0 (ServiceData, 1); + + sd->refcount = 1; + sd->name = g_strdup (name); + + return sd; +} + +static void +service_data_ref (ServiceData *sd) +{ + sd->refcount += 1; +} + +static void +service_data_unref (ServiceData *sd) +{ + sd->refcount -= 1; + if (sd->refcount == 0) + { + g_free (sd->name); + g_free (sd); + } +} + +typedef struct +{ + GtkWidget *window; + GtkWidget *treeview; + GtkWidget *service_menu; + + GSList *services; + +} TreeWindow; + +static void +window_closed_callback (GtkWidget *window, + TreeWindow *w) +{ + g_assert (window == w->window); + w->window = NULL; + gtk_main_quit (); +} + +static TreeWindow* +tree_window_new (void) +{ + TreeWindow *w; + GtkWidget *sw; + GtkWidget *vbox; + GtkWidget *hbox; + + /* Should use glade, blah */ + + w = g_new0 (TreeWindow, 1); + w->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title (GTK_WINDOW (w->window), "D-BUS Viewer"); + gtk_window_set_default_size (GTK_WINDOW (w->window), 400, 500); + + g_signal_connect (w->window, "destroy", G_CALLBACK (window_closed_callback), + w); + gtk_container_set_border_width (GTK_CONTAINER (w->window), 6); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (w->window), vbox); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (vbox), hbox); + + /* Create tree view */ + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_box_pack_start (GTK_BOX (hbox), sw, TRUE, TRUE, 0); + + w->treeview = dbus_tree_view_new (); + + gtk_container_add (GTK_CONTAINER (sw), w->treeview); + + /* Create services option menu */ + + + + /* Show everything */ + gtk_widget_show_all (w->window); + + return w; +} + +static void +show_error_dialog (GtkWindow *transient_parent, + GtkWidget **weak_ptr, + const char *message_format, + ...) +{ + char *message; + va_list args; + + if (message_format) + { + va_start (args, message_format); + message = g_strdup_vprintf (message_format, args); + va_end (args); + } + else + message = NULL; + + if (weak_ptr == NULL || *weak_ptr == NULL) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (transient_parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + message); + + g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL); + + if (weak_ptr != NULL) + { + *weak_ptr = dialog; + g_object_add_weak_pointer (G_OBJECT (dialog), (void**)weak_ptr); + } + + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + + gtk_widget_show_all (dialog); + } + else + { + g_return_if_fail (GTK_IS_MESSAGE_DIALOG (*weak_ptr)); + + gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (*weak_ptr)->label), message); + + gtk_window_present (GTK_WINDOW (*weak_ptr)); + } +} + +static void +usage (int ecode) +{ + fprintf (stderr, "dbus-viewer [--version] [--help]\n"); + exit (ecode); +} + +static void +version (void) +{ + printf ("D-BUS Message Bus Viewer %s\n" + "Copyright (C) 2003 Red Hat, Inc.\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", + VERSION); + exit (0); +} + +int +main (int argc, char **argv) +{ + const char *prev_arg; + int i; + GSList *files; + gboolean end_of_args; + GSList *tmp; + + bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + end_of_args = FALSE; + files = NULL; + prev_arg = NULL; + i = 1; + while (i < argc) + { + const char *arg = argv[i]; + + if (!end_of_args) + { + if (strcmp (arg, "--help") == 0 || + strcmp (arg, "-h") == 0 || + strcmp (arg, "-?") == 0) + usage (0); + else if (strcmp (arg, "--version") == 0) + version (); + else if (arg[0] == '-' && + arg[1] == '-' && + arg[2] == '\0') + end_of_args = TRUE; + else if (arg[0] == '-') + { + usage (1); + } + else + { + files = g_slist_prepend (files, (char*) arg); + } + } + else + files = g_slist_prepend (files, (char*) arg); + + prev_arg = arg; + + ++i; + } + + files = g_slist_reverse (files); + + tmp = files; + while (tmp != NULL) + { + NodeInfo *node; + GError *error; + const char *filename; + + filename = tmp->data; + + error = NULL; + node = description_load_from_file (filename, + &error); + if (node == NULL) + { + g_assert (error != NULL); + show_error_dialog (NULL, NULL, + _("Unable to load \"%s\": %s\n"), + filename, error->message); + g_error_free (error); + } + else + { + TreeWindow *w; + char **path; + const char *name; + + name = node_info_get_name (node); + if (name == NULL || + name[0] != '/') + { + g_printerr (_("Assuming root node of \"%s\" is at path /, since no absolute path is specified"), filename); + name = "/"; + } + + path = _dbus_gutils_split_path (name); + + w = tree_window_new (); + dbus_tree_view_update (GTK_TREE_VIEW (w->treeview), + (const char**) path, + node); + node_info_unref (node); + + g_strfreev (path); + } + + tmp = tmp->next; + } + + gtk_main (); + + return 0; +} + + + + + + -- cgit v1.2.1 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. --- ChangeLog | 36 ++ 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 +- doc/TODO | 3 + doc/dbus-specification.sgml | 86 ++-- test/data/incomplete-messages/missing-body.message | 6 +- test/data/invalid-messages/array-of-nil.message | 7 +- .../array-with-mixed-types.message | 7 +- .../invalid-messages/bad-boolean-array.message | 5 +- test/data/invalid-messages/bad-boolean.message | 5 +- test/data/invalid-messages/bad-endian.message | 5 +- test/data/invalid-messages/local-namespace.message | 5 +- test/data/invalid-messages/no-dot-in-name.message | 4 +- .../not-nul-header-padding.message | 6 +- test/data/invalid-messages/overlong-name.message | 4 +- .../too-little-header-padding.message | 6 +- .../too-much-header-padding-by-far.message | 6 +- .../too-much-header-padding.message | 6 +- test/data/invalid-messages/too-short-dict.message | 4 +- .../array-of-array-of-uint32.message | 2 +- test/data/valid-messages/dict-simple.message | 2 +- test/data/valid-messages/emptiness.message | 2 +- test/data/valid-messages/lots-of-arguments.message | 2 +- test/data/valid-messages/no-padding.message | 2 +- test/data/valid-messages/opposite-endian.message | 2 +- test/data/valid-messages/recursive-types.message | 1 + test/data/valid-messages/simplest-manual.message | 6 +- .../standard-acquire-service.message | 8 +- test/data/valid-messages/standard-hello.message | 8 +- .../valid-messages/standard-list-services.message | 8 +- .../valid-messages/standard-service-exists.message | 8 +- .../valid-messages/unknown-header-field.message | 2 +- 35 files changed, 460 insertions(+), 417 deletions(-) diff --git a/ChangeLog b/ChangeLog index caa4a754..64d29e8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +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. + 2003-09-15 Havoc Pennington * dbus/dbus-pending-call.c: add the get/set object data 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" diff --git a/doc/TODO b/doc/TODO index 5c2b149c..caa8856f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -86,3 +86,6 @@ - I don't want to introduce DBusObject, but refcounting and object data could still be factored out into an internal "base class" perhaps. + + - Header fields names are required to be aligned on a 4 byte boundary + at the moment. No alignment should be neccessary. diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index 5d2982fc..a2dd1b13 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -257,22 +257,22 @@ In addition to the required header information mentioned in , the header may contain zero or more named - header fields. These fields are named to allow - future versions of this protocol specification to - add new fields; implementations must ignore fields - they do not understand. Implementations must not - invent their own header fields; only changes to + header fields. Future versions of this protocol + specification may add new fields. Implementations must + ignore fields they do not understand. Implementations + must not invent their own header fields; only changes to this specification may introduce new header fields. - Header field names MUST consist of 4 non-nul bytes. The field name is - NOT nul terminated; it occupies exactly 4 bytes. Following the name, the - field MUST have a type code represented as a single unsigned byte, and - then a properly-aligned value of that type. See for a description of how each type - is encoded. If an implementation sees a header field name that it does - not understand, it MUST ignore that field. + Header fields MUST be aligned to a 4-byte boundary. Header field + names MUST consist of a single byte, possible values of which are + defined below. Following the name, the field MUST have a type code + represented as a single unsigned byte, and then a properly-aligned + value of that type. See for a description of how each + type is encoded. If an implementation sees a header field name that + it does not understand, it MUST ignore that field. @@ -281,51 +281,65 @@ - Name + Conventional Name + Decimal Value Type Description - path + INVALID + 0 + INVALID + Not a valid field name (error if it appears in a message) + + + PATH + 1 STRING The object to send the message to; objects are identified by a path, "/foo/bar" - ifce + INTERFACE + 2 STRING The interface to invoke a method call on, or that a signal is emitted from. e.g. "org.freedesktop.Introspectable" - mebr + MEMBER + 3 STRING The member, either the method name or signal name. e.g. "Frobate" - ernm + ERROR_NAME + 4 STRING The name of the error that occurred, for errors - rply + REPLY_SERIAL + 5 UINT32 The serial number of the message this message is a reply to. (The serial number is one of the mandatory header fields, see .) - srvc + SERVICE + 6 STRING The name of the service this message should be routed to. Only used in combination with the message bus, see . - sdrs + SENDER_SERVICE + 7 STRING Sender service. The name of the base service that sent this message. The message bus fills in this field; the field is @@ -595,24 +609,24 @@ messages map naturally to methods on objects in a typical program. - A method call message is expected to have a 'mebr' header field + A method call message is expected to have a MEMBER header field indicating the name of the method. Optionally, the message has an - 'ifce' field giving the interface the method is a part of. In the - absence of an 'ifce' field, if two interfaces on the same object have + INTERFACE field giving the interface the method is a part of. In the + absence of an INTERFACE field, if two interfaces on the same object have a method with the same name, it is undefined which of the two methods will be invoked. Implementations may also choose to return an error in this ambiguous case. However, if a method name is unique implementations should not require an interface field. - Method call messages also include a 'path' field indicating the + Method call messages also include a PATH field indicating the object to invoke the method on. If the call is passing through - a message bus, the message will also have a 'srvc' field giving + a message bus, the message will also have a SERVICE field giving the service to receive the message. When an application handles a method call message, it is expected to - return a reply. The reply is identified by a 'rply' header field + return a reply. The reply is identified by a REPLY_SERIAL header field indicating the serial number of the METHOD_CALL being replied to. The reply can have one of two types; either METHOD_RETURN or ERROR. @@ -673,9 +687,9 @@ Unlike method calls, signal emissions have no replies. A signal emission is simply a single message of type SIGNAL. - It must have three header fields: 'path' giving the object - the signal was emitted from, plus 'ifce' and 'mebr' giving the - fully-qualified name of the signal. + It must have three header fields: PATH giving the object + the signal was emitted from, plus INTERFACE and MEMBER giving + the fully-qualified name of the signal. @@ -688,9 +702,9 @@ org.freedesktop.DBus.ActivateService (in STRING service_name, in UINT32 flags, out UINT32 resultcode) - This means ifce = org.freedesktop.DBus, mebr = ActivateService, + This means INTERFACE = org.freedesktop.DBus, MEMBER = ActivateService, METHOD_CALL arguments are STRING and UINT32, METHOD_RETURN argument - is UINT32. Remember that the 'mebr' field can't contain any '.' (period) + is UINT32. Remember that the MEMBER field can't contain any '.' (period) characters so it's known that the last part of the name in the "IDL" is the member name. @@ -1270,18 +1284,18 @@ the new owner of the service. - Messages may have a srvc field (see SERVICE field (see ). When the message bus - receives a message, if the srvc field is absent, the + receives a message, if the SERVICE field is absent, the message is taken to be a standard peer-to-peer message and interpreted by the message bus itself. For example, sending an org.freedesktop.Peer.Ping message with no - srvc will cause the message bus itself to reply + SERVICE will cause the message bus itself to reply to the ping immediately; the message bus would never make this message visible to other applications. - If the srvc field is present, then it indicates a + If the SERVICE field is present, then it indicates a request for the message bus to route the message. In the usual case, messages are routed to the owner of the named service. Messages may also be broadcast @@ -1292,7 +1306,7 @@ Continuing the org.freedesktop.Peer.Ping example, if - the ping message were sent with a srvc name of + the ping message were sent with a SERVICE name of com.yoyodyne.Screensaver, then the ping would be forwarded, and the Yoyodyne Corporation screensaver application would be expected to reply to the ping. If diff --git a/test/data/incomplete-messages/missing-body.message b/test/data/incomplete-messages/missing-body.message index 69e371e0..138e9ea5 100644 --- a/test/data/incomplete-messages/missing-body.message +++ b/test/data/incomplete-messages/missing-body.message @@ -1,14 +1,14 @@ ## message that's missing an expected body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' -END_LENGTH Header ALIGN 8 +END_LENGTH Header ## create the body, then chop it off START_LENGTH Body diff --git a/test/data/invalid-messages/array-of-nil.message b/test/data/invalid-messages/array-of-nil.message index 4810d318..7f0ac718 100644 --- a/test/data/invalid-messages/array-of-nil.message +++ b/test/data/invalid-messages/array-of-nil.message @@ -2,15 +2,16 @@ VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' -END_LENGTH Header ALIGN 8 +END_LENGTH Header + START_LENGTH Body TYPE ARRAY TYPE NIL diff --git a/test/data/invalid-messages/array-with-mixed-types.message b/test/data/invalid-messages/array-with-mixed-types.message index 1bdd549b..4455c898 100644 --- a/test/data/invalid-messages/array-with-mixed-types.message +++ b/test/data/invalid-messages/array-with-mixed-types.message @@ -3,15 +3,16 @@ VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' -END_LENGTH Header ALIGN 8 +END_LENGTH Header + START_LENGTH Body TYPE ARRAY diff --git a/test/data/invalid-messages/bad-boolean-array.message b/test/data/invalid-messages/bad-boolean-array.message index e4df1903..91ad5ef1 100644 --- a/test/data/invalid-messages/bad-boolean-array.message +++ b/test/data/invalid-messages/bad-boolean-array.message @@ -3,15 +3,16 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' ALIGN 8 END_LENGTH Header + START_LENGTH Body TYPE ARRAY TYPE BOOLEAN diff --git a/test/data/invalid-messages/bad-boolean.message b/test/data/invalid-messages/bad-boolean.message index 7b518d57..cd588ad8 100644 --- a/test/data/invalid-messages/bad-boolean.message +++ b/test/data/invalid-messages/bad-boolean.message @@ -3,15 +3,16 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' ALIGN 8 END_LENGTH Header + START_LENGTH Body TYPE BOOLEAN BYTE 3 diff --git a/test/data/invalid-messages/bad-endian.message b/test/data/invalid-messages/bad-endian.message index c08f0188..8d609244 100644 --- a/test/data/invalid-messages/bad-endian.message +++ b/test/data/invalid-messages/bad-endian.message @@ -8,15 +8,14 @@ BYTE 0 LENGTH Header LENGTH Body -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' ALIGN 8 - END_LENGTH Header START_LENGTH Body diff --git a/test/data/invalid-messages/local-namespace.message b/test/data/invalid-messages/local-namespace.message index f485d70c..dad98a77 100644 --- a/test/data/invalid-messages/local-namespace.message +++ b/test/data/invalid-messages/local-namespace.message @@ -4,14 +4,15 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Local' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Disconnected' ALIGN 8 END_LENGTH Header + START_LENGTH Body END_LENGTH Body diff --git a/test/data/invalid-messages/no-dot-in-name.message b/test/data/invalid-messages/no-dot-in-name.message index 53e288d0..131be05d 100644 --- a/test/data/invalid-messages/no-dot-in-name.message +++ b/test/data/invalid-messages/no-dot-in-name.message @@ -3,10 +3,10 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'NoDotInHere' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' diff --git a/test/data/invalid-messages/not-nul-header-padding.message b/test/data/invalid-messages/not-nul-header-padding.message index f98812c2..a12c0fa7 100644 --- a/test/data/invalid-messages/not-nul-header-padding.message +++ b/test/data/invalid-messages/not-nul-header-padding.message @@ -3,14 +3,14 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' -FIELD_NAME unkn +HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 diff --git a/test/data/invalid-messages/overlong-name.message b/test/data/invalid-messages/overlong-name.message index 4108a037..4fd7025e 100644 --- a/test/data/invalid-messages/overlong-name.message +++ b/test/data/invalid-messages/overlong-name.message @@ -2,11 +2,11 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.foo.bar.this.is.really.long 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' diff --git a/test/data/invalid-messages/too-little-header-padding.message b/test/data/invalid-messages/too-little-header-padding.message index f6e7af4b..894e4c3e 100644 --- a/test/data/invalid-messages/too-little-header-padding.message +++ b/test/data/invalid-messages/too-little-header-padding.message @@ -3,14 +3,14 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' -FIELD_NAME unkn +HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 diff --git a/test/data/invalid-messages/too-much-header-padding-by-far.message b/test/data/invalid-messages/too-much-header-padding-by-far.message index 6cc5b391..b74f559b 100644 --- a/test/data/invalid-messages/too-much-header-padding-by-far.message +++ b/test/data/invalid-messages/too-much-header-padding-by-far.message @@ -3,14 +3,14 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' -FIELD_NAME unkn +HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 diff --git a/test/data/invalid-messages/too-much-header-padding.message b/test/data/invalid-messages/too-much-header-padding.message index 6cf004b9..01111b63 100644 --- a/test/data/invalid-messages/too-much-header-padding.message +++ b/test/data/invalid-messages/too-much-header-padding.message @@ -3,14 +3,14 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' -FIELD_NAME unkn +HEADER_FIELD UNKNOWN TYPE STRING STRING 'a' ALIGN 8 diff --git a/test/data/invalid-messages/too-short-dict.message b/test/data/invalid-messages/too-short-dict.message index 59621126..fde88850 100644 --- a/test/data/invalid-messages/too-short-dict.message +++ b/test/data/invalid-messages/too-short-dict.message @@ -2,10 +2,10 @@ VALID_HEADER method_call -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' diff --git a/test/data/valid-messages/array-of-array-of-uint32.message b/test/data/valid-messages/array-of-array-of-uint32.message index 692eca06..e12186b1 100644 --- a/test/data/valid-messages/array-of-array-of-uint32.message +++ b/test/data/valid-messages/array-of-array-of-uint32.message @@ -2,8 +2,8 @@ VALID_HEADER method_call REQUIRED_FIELDS -END_LENGTH Header ALIGN 8 +END_LENGTH Header START_LENGTH Body TYPE ARRAY diff --git a/test/data/valid-messages/dict-simple.message b/test/data/valid-messages/dict-simple.message index 6986d439..fa6927df 100644 --- a/test/data/valid-messages/dict-simple.message +++ b/test/data/valid-messages/dict-simple.message @@ -2,8 +2,8 @@ VALID_HEADER method_call REQUIRED_FIELDS -END_LENGTH Header ALIGN 8 +END_LENGTH Header START_LENGTH Body TYPE DICT LENGTH Dict diff --git a/test/data/valid-messages/emptiness.message b/test/data/valid-messages/emptiness.message index dbf531ca..32042c01 100644 --- a/test/data/valid-messages/emptiness.message +++ b/test/data/valid-messages/emptiness.message @@ -2,8 +2,8 @@ VALID_HEADER method_call REQUIRED_FIELDS -END_LENGTH Header ALIGN 8 +END_LENGTH Header START_LENGTH Body TYPE STRING INT32 0 diff --git a/test/data/valid-messages/lots-of-arguments.message b/test/data/valid-messages/lots-of-arguments.message index 993755ab..d3f6a4ee 100644 --- a/test/data/valid-messages/lots-of-arguments.message +++ b/test/data/valid-messages/lots-of-arguments.message @@ -2,8 +2,8 @@ VALID_HEADER method_call REQUIRED_FIELDS -END_LENGTH Header ALIGN 8 +END_LENGTH Header START_LENGTH Body TYPE NIL TYPE BYTE diff --git a/test/data/valid-messages/no-padding.message b/test/data/valid-messages/no-padding.message index e6d27d9d..94df4d45 100644 --- a/test/data/valid-messages/no-padding.message +++ b/test/data/valid-messages/no-padding.message @@ -7,7 +7,7 @@ REQUIRED_FIELDS ## this byte array is filled with zeros to the natural length ## of the header -FIELD_NAME unkn +HEADER_FIELD UNKNOWN TYPE ARRAY TYPE BYTE ALIGN 4 diff --git a/test/data/valid-messages/opposite-endian.message b/test/data/valid-messages/opposite-endian.message index c638b7b0..90949dd2 100644 --- a/test/data/valid-messages/opposite-endian.message +++ b/test/data/valid-messages/opposite-endian.message @@ -7,7 +7,7 @@ VALID_HEADER method_call REQUIRED_FIELDS -FIELD_NAME unkn +HEADER_FIELD UNKNOWN TYPE INT32 INT32 0xfeeb diff --git a/test/data/valid-messages/recursive-types.message b/test/data/valid-messages/recursive-types.message index 192fd9b7..e306fd1f 100644 --- a/test/data/valid-messages/recursive-types.message +++ b/test/data/valid-messages/recursive-types.message @@ -5,6 +5,7 @@ VALID_HEADER method_call REQUIRED_FIELDS +ALIGN 8 END_LENGTH Header START_LENGTH Body diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message index 9779234b..5a5b4105 100644 --- a/test/data/valid-messages/simplest-manual.message +++ b/test/data/valid-messages/simplest-manual.message @@ -11,13 +11,13 @@ LENGTH Body ## client serial INT32 7 -FIELD_NAME path +HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/foo' -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.Foo' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Bar' diff --git a/test/data/valid-messages/standard-acquire-service.message b/test/data/valid-messages/standard-acquire-service.message index f313061f..a42a639c 100644 --- a/test/data/valid-messages/standard-acquire-service.message +++ b/test/data/valid-messages/standard-acquire-service.message @@ -1,16 +1,16 @@ # Standard org.freedesktop.DBus.AcquireService message VALID_HEADER method_call -FIELD_NAME path +HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'AcquireService' -FIELD_NAME srvc +HEADER_FIELD SERVICE TYPE STRING STRING 'org.freedesktop.DBus' ALIGN 8 diff --git a/test/data/valid-messages/standard-hello.message b/test/data/valid-messages/standard-hello.message index 795ede74..50d4e0ff 100644 --- a/test/data/valid-messages/standard-hello.message +++ b/test/data/valid-messages/standard-hello.message @@ -1,16 +1,16 @@ # Standard org.freedesktop.DBus.Hello message VALID_HEADER method_call -FIELD_NAME path +HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'Hello' -FIELD_NAME srvc +HEADER_FIELD SERVICE TYPE STRING STRING 'org.freedesktop.DBus' ALIGN 8 diff --git a/test/data/valid-messages/standard-list-services.message b/test/data/valid-messages/standard-list-services.message index 4c9c7c66..10c9a2f7 100644 --- a/test/data/valid-messages/standard-list-services.message +++ b/test/data/valid-messages/standard-list-services.message @@ -1,16 +1,16 @@ # Standard org.freedesktop.DBus.ListServices message VALID_HEADER method_call -FIELD_NAME path +HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'ListServices' -FIELD_NAME srvc +HEADER_FIELD SERVICES TYPE STRING STRING 'org.freedesktop.DBus' ALIGN 8 diff --git a/test/data/valid-messages/standard-service-exists.message b/test/data/valid-messages/standard-service-exists.message index ce14811a..c3b715bc 100644 --- a/test/data/valid-messages/standard-service-exists.message +++ b/test/data/valid-messages/standard-service-exists.message @@ -1,16 +1,16 @@ # Standard org.freedesktop.DBus.ServiceExists message VALID_HEADER method_call -FIELD_NAME path +HEADER_FIELD PATH TYPE OBJECT_PATH OBJECT_PATH '/org/freedesktop/DBus' -FIELD_NAME ifce +HEADER_FIELD INTERFACE TYPE STRING STRING 'org.freedesktop.DBus' -FIELD_NAME mebr +HEADER_FIELD MEMBER TYPE STRING STRING 'ServiceExists' -FIELD_NAME srvc +HEADER_FIELD SERVICE TYPE STRING STRING 'org.freedesktop.DBus' ALIGN 8 diff --git a/test/data/valid-messages/unknown-header-field.message b/test/data/valid-messages/unknown-header-field.message index 5d95f812..973def68 100644 --- a/test/data/valid-messages/unknown-header-field.message +++ b/test/data/valid-messages/unknown-header-field.message @@ -3,7 +3,7 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call REQUIRED_FIELDS -FIELD_NAME unkn +HEADER_FIELD UNKNOWN TYPE INT32 INT32 0xfeeb ALIGN 8 -- cgit v1.2.1 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) --- ChangeLog | 35 ++ bus/Makefile.am | 2 + bus/bus.c | 65 +- bus/bus.h | 71 ++- bus/config-parser.c | 102 ++-- bus/connection.c | 123 +++- bus/connection.h | 13 +- bus/dbus-daemon-1.1.in | 49 +- bus/dispatch.c | 312 +++++++--- bus/dispatch.h | 3 +- bus/driver.c | 164 ++++- bus/policy.c | 39 +- bus/policy.h | 3 + bus/session.conf.in | 5 +- bus/signals.c | 774 ++++++++++++++++++++++++ bus/signals.h | 83 +++ bus/system.conf.in | 4 +- bus/test-main.c | 6 + bus/test.h | 1 + dbus/dbus-errors.h | 13 +- dbus/dbus-mainloop.c | 2 +- dbus/dbus-protocol.h | 1 - dbus/dbus-transport.c | 2 + doc/TODO | 9 +- glib/dbus-gproxy.c | 2 +- test/data/valid-config-files/many-rules.conf | 16 +- test/data/valid-config-files/system.d/test.conf | 2 +- tools/dbus-send.c | 2 +- 28 files changed, 1697 insertions(+), 206 deletions(-) create mode 100644 bus/signals.c create mode 100644 bus/signals.h diff --git a/ChangeLog b/ChangeLog index 64d29e8d..68dfde4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +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) + 2003-09-21 Mark McLoughlin * doc/dbus-specification.sgml: Change the header field name diff --git a/bus/Makefile.am b/bus/Makefile.am index 27735077..bc728801 100644 --- a/bus/Makefile.am +++ b/bus/Makefile.am @@ -44,6 +44,8 @@ BUS_SOURCES= \ policy.h \ services.c \ services.h \ + signals.c \ + signals.h \ test.c \ test.h \ utils.c \ diff --git a/bus/bus.c b/bus/bus.c index 1b461fe3..4087334e 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -28,6 +28,7 @@ #include "utils.h" #include "policy.h" #include "config-parser.h" +#include "signals.h" #include #include #include @@ -44,6 +45,7 @@ struct BusContext BusActivation *activation; BusRegistry *registry; BusPolicy *policy; + BusMatchmaker *matchmaker; DBusUserDatabase *user_database; BusLimits limits; }; @@ -505,6 +507,13 @@ bus_context_new (const DBusString *config_file, goto failed; } + context->matchmaker = bus_matchmaker_new (); + if (context->matchmaker == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + context->policy = bus_config_parser_steal_policy (parser); _dbus_assert (context->policy != NULL); @@ -715,6 +724,12 @@ bus_context_unref (BusContext *context) _dbus_loop_unref (context->loop); context->loop = NULL; } + + if (context->matchmaker) + { + bus_matchmaker_unref (context->matchmaker); + context->matchmaker = NULL; + } dbus_free (context->type); dbus_free (context->address); @@ -771,6 +786,12 @@ bus_context_get_activation (BusContext *context) return context->activation; } +BusMatchmaker* +bus_context_get_matchmaker (BusContext *context) +{ + return context->matchmaker; +} + DBusLoop* bus_context_get_loop (BusContext *context) { @@ -845,18 +866,33 @@ bus_context_get_max_services_per_connection (BusContext *context) return context->limits.max_services_per_connection; } +int +bus_context_get_max_match_rules_per_connection (BusContext *context) +{ + return context->limits.max_match_rules_per_connection; +} + dbus_bool_t bus_context_check_security_policy (BusContext *context, DBusConnection *sender, - DBusConnection *recipient, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, DBusMessage *message, DBusError *error) { BusClientPolicy *sender_policy; BusClientPolicy *recipient_policy; - /* NULL sender/receiver means the bus driver */ + /* NULL sender, proposed_recipient means the bus driver. NULL + * addressed_recipient means the message didn't specify an explicit + * target. If proposed_recipient is NULL, then addressed_recipient + * is also NULL but is implicitly the bus driver. + */ + _dbus_assert (proposed_recipient == NULL || + (dbus_message_get_destination (message) == NULL || + addressed_recipient != NULL)); + if (sender != NULL) { if (bus_connection_is_active (sender)) @@ -869,7 +905,7 @@ bus_context_check_security_policy (BusContext *context, /* Policy for inactive connections is that they can only send * the hello message to the bus driver */ - if (recipient == NULL && + if (proposed_recipient == NULL && dbus_message_is_method_call (message, DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, "Hello")) @@ -897,15 +933,15 @@ bus_context_check_security_policy (BusContext *context, _dbus_assert ((sender != NULL && sender_policy != NULL) || (sender == NULL && sender_policy == NULL)); - if (recipient != NULL) + if (proposed_recipient != NULL) { /* only the bus driver can send to an inactive recipient (as it * owns no services, so other apps can't address it). Inactive * recipients can receive any message. */ - if (bus_connection_is_active (recipient)) + if (bus_connection_is_active (proposed_recipient)) { - recipient_policy = bus_connection_get_policy (recipient); + recipient_policy = bus_connection_get_policy (proposed_recipient); _dbus_assert (recipient_policy != NULL); } else if (sender == NULL) @@ -922,13 +958,13 @@ bus_context_check_security_policy (BusContext *context, else recipient_policy = NULL; - _dbus_assert ((recipient != NULL && recipient_policy != NULL) || - (recipient != NULL && sender == NULL && recipient_policy == NULL) || - (recipient == NULL && recipient_policy == NULL)); + _dbus_assert ((proposed_recipient != NULL && recipient_policy != NULL) || + (proposed_recipient != NULL && sender == NULL && recipient_policy == NULL) || + (proposed_recipient == NULL && recipient_policy == NULL)); if (sender_policy && !bus_client_policy_check_can_send (sender_policy, - context->registry, recipient, + context->registry, proposed_recipient, message)) { const char *dest = dbus_message_get_destination (message); @@ -951,6 +987,7 @@ bus_context_check_security_policy (BusContext *context, if (recipient_policy && !bus_client_policy_check_can_receive (recipient_policy, context->registry, sender, + addressed_recipient, proposed_recipient, message)) { const char *dest = dbus_message_get_destination (message); @@ -971,14 +1008,16 @@ bus_context_check_security_policy (BusContext *context, } /* See if limits on size have been exceeded */ - if (recipient && - dbus_connection_get_outgoing_size (recipient) > + if (proposed_recipient && + dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) { const char *dest = dbus_message_get_destination (message); dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "The destination service \"%s\" has a full message queue", - dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS); + dest ? dest : (proposed_recipient ? + bus_connection_get_name (proposed_recipient) : + DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)); _dbus_verbose ("security policy disallowing message due to full message queue\n"); return FALSE; } diff --git a/bus/bus.h b/bus/bus.h index 8f32d7a9..5809321a 100644 --- a/bus/bus.h +++ b/bus/bus.h @@ -40,7 +40,8 @@ typedef struct BusPolicyRule BusPolicyRule; typedef struct BusRegistry BusRegistry; typedef struct BusService BusService; typedef struct BusTransaction BusTransaction; - +typedef struct BusMatchmaker BusMatchmaker; +typedef struct BusMatchRule BusMatchRule; typedef struct { @@ -54,40 +55,44 @@ typedef struct int max_connections_per_user; /**< Max number of connections auth'd as same user */ int max_pending_activations; /**< Max number of pending activations for the entire bus */ int max_services_per_connection; /**< Max number of owned services for a single connection */ + int max_match_rules_per_connection; /**< Max number of match rules for a single connection */ } BusLimits; -BusContext* bus_context_new (const DBusString *config_file, - dbus_bool_t force_fork, - int print_addr_fd, - int print_pid_fd, - DBusError *error); -void bus_context_shutdown (BusContext *context); -void bus_context_ref (BusContext *context); -void bus_context_unref (BusContext *context); -const char* bus_context_get_type (BusContext *context); -const char* bus_context_get_address (BusContext *context); -BusRegistry* bus_context_get_registry (BusContext *context); -BusConnections* bus_context_get_connections (BusContext *context); -BusActivation* bus_context_get_activation (BusContext *context); -DBusLoop* bus_context_get_loop (BusContext *context); -DBusUserDatabase* bus_context_get_user_database (BusContext *context); -dbus_bool_t bus_context_allow_user (BusContext *context, - unsigned long uid); -BusClientPolicy* bus_context_create_client_policy (BusContext *context, - DBusConnection *connection, - DBusError *error); +BusContext* bus_context_new (const DBusString *config_file, + dbus_bool_t force_fork, + int print_addr_fd, + int print_pid_fd, + DBusError *error); +void bus_context_shutdown (BusContext *context); +void bus_context_ref (BusContext *context); +void bus_context_unref (BusContext *context); +const char* bus_context_get_type (BusContext *context); +const char* bus_context_get_address (BusContext *context); +BusRegistry* bus_context_get_registry (BusContext *context); +BusConnections* bus_context_get_connections (BusContext *context); +BusActivation* bus_context_get_activation (BusContext *context); +BusMatchmaker* bus_context_get_matchmaker (BusContext *context); +DBusLoop* bus_context_get_loop (BusContext *context); +DBusUserDatabase* bus_context_get_user_database (BusContext *context); +dbus_bool_t bus_context_allow_user (BusContext *context, + unsigned long uid); +BusClientPolicy* bus_context_create_client_policy (BusContext *context, + DBusConnection *connection, + DBusError *error); +int bus_context_get_activation_timeout (BusContext *context); +int bus_context_get_auth_timeout (BusContext *context); +int bus_context_get_max_completed_connections (BusContext *context); +int bus_context_get_max_incomplete_connections (BusContext *context); +int bus_context_get_max_connections_per_user (BusContext *context); +int bus_context_get_max_pending_activations (BusContext *context); +int bus_context_get_max_services_per_connection (BusContext *context); +int bus_context_get_max_match_rules_per_connection (BusContext *context); +dbus_bool_t bus_context_check_security_policy (BusContext *context, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + DBusError *error); -int bus_context_get_activation_timeout (BusContext *context); -int bus_context_get_auth_timeout (BusContext *context); -int bus_context_get_max_completed_connections (BusContext *context); -int bus_context_get_max_incomplete_connections (BusContext *context); -int bus_context_get_max_connections_per_user (BusContext *context); -int bus_context_get_max_pending_activations (BusContext *context); -int bus_context_get_max_services_per_connection (BusContext *context); -dbus_bool_t bus_context_check_security_policy (BusContext *context, - DBusConnection *sender, - DBusConnection *recipient, - DBusMessage *message, - DBusError *error); #endif /* BUS_BUS_H */ diff --git a/bus/config-parser.c b/bus/config-parser.c index cbc239f9..7b9b962d 100644 --- a/bus/config-parser.c +++ b/bus/config-parser.c @@ -334,6 +334,8 @@ bus_config_parser_new (const DBusString *basedir, parser->limits.max_pending_activations = 256; parser->limits.max_services_per_connection = 256; + + parser->limits.max_match_rules_per_connection = 128; parser->refcount = 1; @@ -837,15 +839,16 @@ append_rule_from_element (BusConfigParser *parser, const char *send_interface; const char *send_member; const char *send_error; - const char *send_service; + const char *send_destination; const char *send_path; const char *send_type; const char *receive_interface; const char *receive_member; const char *receive_error; - const char *receive_service; + const char *receive_sender; const char *receive_path; const char *receive_type; + const char *eavesdrop; const char *own; const char *user; const char *group; @@ -858,25 +861,26 @@ append_rule_from_element (BusConfigParser *parser, "send_interface", &send_interface, "send_member", &send_member, "send_error", &send_error, - "send_service", &send_service, + "send_destination", &send_destination, "send_path", &send_path, "send_type", &send_type, "receive_interface", &receive_interface, "receive_member", &receive_member, "receive_error", &receive_error, - "receive_service", &receive_service, + "receive_sender", &receive_sender, "receive_path", &receive_path, "receive_type", &receive_type, + "eavesdrop", &eavesdrop, "own", &own, "user", &user, "group", &group, NULL)) return FALSE; - if (!(send_interface || send_member || send_error || send_service || + if (!(send_interface || send_member || send_error || send_destination || send_type || send_path || - receive_interface || receive_member || receive_error || receive_service || - receive_type || receive_path || + receive_interface || receive_member || receive_error || receive_sender || + receive_type || receive_path || eavesdrop || own || user || group)) { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -902,17 +906,20 @@ append_rule_from_element (BusConfigParser *parser, * interface + member * error * - * base send_ can combine with send_service, send_path, send_type - * base receive_ with receive_service, receive_path, receive_type + * base send_ can combine with send_destination, send_path, send_type + * base receive_ with receive_sender, receive_path, receive_type, eavesdrop * * user, group, own must occur alone + * + * Pretty sure the below stuff is broken, FIXME think about it more. */ if (((send_interface && send_error) || (send_interface && receive_interface) || (send_interface && receive_member) || (send_interface && receive_error) || - (send_interface && receive_service) || + (send_interface && receive_sender) || + (send_interface && eavesdrop) || (send_interface && own) || (send_interface && user) || (send_interface && group)) || @@ -921,7 +928,8 @@ append_rule_from_element (BusConfigParser *parser, (send_member && receive_interface) || (send_member && receive_member) || (send_member && receive_error) || - (send_member && receive_service) || + (send_member && receive_sender) || + (send_member && eavesdrop) || (send_member && own) || (send_member && user) || (send_member && group)) || @@ -929,23 +937,26 @@ append_rule_from_element (BusConfigParser *parser, ((send_error && receive_interface) || (send_error && receive_member) || (send_error && receive_error) || - (send_error && receive_service) || + (send_error && receive_sender) || + (send_error && eavesdrop) || (send_error && own) || (send_error && user) || (send_error && group)) || - ((send_service && receive_interface) || - (send_service && receive_member) || - (send_service && receive_error) || - (send_service && receive_service) || - (send_service && own) || - (send_service && user) || - (send_service && group)) || + ((send_destination && receive_interface) || + (send_destination && receive_member) || + (send_destination && receive_error) || + (send_destination && receive_sender) || + (send_destination && eavesdrop) || + (send_destination && own) || + (send_destination && user) || + (send_destination && group)) || ((send_type && receive_interface) || (send_type && receive_member) || (send_type && receive_error) || - (send_type && receive_service) || + (send_type && receive_sender) || + (send_type && eavesdrop) || (send_type && own) || (send_type && user) || (send_type && group)) || @@ -953,7 +964,8 @@ append_rule_from_element (BusConfigParser *parser, ((send_path && receive_interface) || (send_path && receive_member) || (send_path && receive_error) || - (send_path && receive_service) || + (send_path && receive_sender) || + (send_path && eavesdrop) || (send_path && own) || (send_path && user) || (send_path && group)) || @@ -967,19 +979,22 @@ append_rule_from_element (BusConfigParser *parser, (receive_member && own) || (receive_member && user) || (receive_member && group)) || - + ((receive_error && own) || (receive_error && user) || (receive_error && group)) || + ((eavesdrop && own) || + (eavesdrop && user) || + (eavesdrop && group)) || + ((own && user) || (own && group)) || ((user && group))) { dbus_set_error (error, DBUS_ERROR_FAILED, - "Invalid combination of attributes on element <%s>, " - "only send_foo/send_service or receive_foo/receive_service may be paired", + "Invalid combination of attributes on element <%s>", element_name); return FALSE; } @@ -991,7 +1006,7 @@ append_rule_from_element (BusConfigParser *parser, */ #define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') - if (send_interface || send_member || send_error || send_service || + if (send_interface || send_member || send_error || send_destination || send_path || send_type) { int message_type; @@ -1002,8 +1017,8 @@ append_rule_from_element (BusConfigParser *parser, send_member = NULL; if (IS_WILDCARD (send_error)) send_error = NULL; - if (IS_WILDCARD (send_service)) - send_service = NULL; + if (IS_WILDCARD (send_destination)) + send_destination = NULL; if (IS_WILDCARD (send_path)) send_path = NULL; if (IS_WILDCARD (send_type)) @@ -1025,13 +1040,13 @@ append_rule_from_element (BusConfigParser *parser, rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); if (rule == NULL) goto nomem; - + rule->d.send.message_type = message_type; rule->d.send.path = _dbus_strdup (send_path); rule->d.send.interface = _dbus_strdup (send_interface); rule->d.send.member = _dbus_strdup (send_member); rule->d.send.error = _dbus_strdup (send_error); - rule->d.send.destination = _dbus_strdup (send_service); + rule->d.send.destination = _dbus_strdup (send_destination); if (send_path && rule->d.send.path == NULL) goto nomem; if (send_interface && rule->d.send.interface == NULL) @@ -1040,11 +1055,11 @@ append_rule_from_element (BusConfigParser *parser, goto nomem; if (send_error && rule->d.send.error == NULL) goto nomem; - if (send_service && rule->d.send.destination == NULL) + if (send_destination && rule->d.send.destination == NULL) goto nomem; } - else if (receive_interface || receive_member || receive_error || receive_service || - receive_path || receive_type) + else if (receive_interface || receive_member || receive_error || receive_sender || + receive_path || receive_type || eavesdrop) { int message_type; @@ -1054,14 +1069,13 @@ append_rule_from_element (BusConfigParser *parser, receive_member = NULL; if (IS_WILDCARD (receive_error)) receive_error = NULL; - if (IS_WILDCARD (receive_service)) - receive_service = NULL; + if (IS_WILDCARD (receive_sender)) + receive_sender = NULL; if (IS_WILDCARD (receive_path)) receive_path = NULL; if (IS_WILDCARD (receive_type)) receive_type = NULL; - message_type = DBUS_MESSAGE_TYPE_INVALID; if (receive_type != NULL) { @@ -1074,17 +1088,31 @@ append_rule_from_element (BusConfigParser *parser, return FALSE; } } + + + if (eavesdrop && + !(strcmp (eavesdrop, "true") == 0 || + strcmp (eavesdrop, "false") == 0)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for eavesdrop attribute, must be true or false", + eavesdrop); + return FALSE; + } rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); if (rule == NULL) goto nomem; + if (eavesdrop) + rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0); + rule->d.receive.message_type = message_type; rule->d.receive.path = _dbus_strdup (receive_path); rule->d.receive.interface = _dbus_strdup (receive_interface); rule->d.receive.member = _dbus_strdup (receive_member); rule->d.receive.error = _dbus_strdup (receive_error); - rule->d.receive.origin = _dbus_strdup (receive_service); + rule->d.receive.origin = _dbus_strdup (receive_sender); if (receive_path && rule->d.receive.path == NULL) goto nomem; if (receive_interface && rule->d.receive.interface == NULL) @@ -1093,7 +1121,7 @@ append_rule_from_element (BusConfigParser *parser, goto nomem; if (receive_error && rule->d.receive.error == NULL) goto nomem; - if (receive_service && rule->d.receive.origin == NULL) + if (receive_sender && rule->d.receive.origin == NULL) goto nomem; } else if (own) diff --git a/bus/connection.c b/bus/connection.c index f6ce4a29..a824576c 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -25,6 +25,7 @@ #include "policy.h" #include "services.h" #include "utils.h" +#include "signals.h" #include #include #include @@ -41,6 +42,7 @@ struct BusConnections BusContext *context; DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */ DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */ + int stamp; /**< Incrementing number */ }; static dbus_int32_t connection_data_slot = -1; @@ -52,6 +54,8 @@ typedef struct DBusConnection *connection; DBusList *services_owned; int n_services_owned; + DBusList *match_rules; + int n_match_rules; char *name; DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */ DBusMessage *oom_message; @@ -60,6 +64,7 @@ typedef struct long connection_tv_sec; /**< Time when we connected (seconds component) */ long connection_tv_usec; /**< Time when we connected (microsec component) */ + int stamp; /**< connections->stamp last time we were traversed */ } BusConnectionData; static dbus_bool_t expire_incomplete_timeout (void *data); @@ -140,12 +145,20 @@ bus_connection_disconnected (DBusConnection *connection) { BusConnectionData *d; BusService *service; - + BusMatchmaker *matchmaker; + d = BUS_CONNECTION_DATA (connection); _dbus_assert (d != NULL); _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n", d->name ? d->name : "(inactive)"); + + /* Delete our match rules */ + if (d->n_match_rules > 0) + { + matchmaker = bus_context_get_matchmaker (d->connections->context); + bus_matchmaker_disconnected (matchmaker, connection); + } /* Drop any service ownership. FIXME Unfortunately, this requires * memory allocation and there doesn't seem to be a good way to @@ -881,6 +894,40 @@ bus_connections_get_context (BusConnections *connections) return connections->context; } +/* + * This is used to avoid covering the same connection twice when + * traversing connections. Note that it assumes we will + * bus_connection_mark_stamp() each connection at least once per + * INT_MAX increments of the global stamp, or wraparound would break + * things. + */ +void +bus_connections_increment_stamp (BusConnections *connections) +{ + connections->stamp += 1; +} + +/* Mark connection with current stamp, return TRUE if it + * didn't already have that stamp + */ +dbus_bool_t +bus_connection_mark_stamp (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + if (d->stamp == d->connections->stamp) + return FALSE; + else + { + d->stamp = d->connections->stamp; + return TRUE; + } +} + BusContext* bus_connection_get_context (DBusConnection *connection) { @@ -929,6 +976,18 @@ bus_connection_get_activation (DBusConnection *connection) return bus_context_get_activation (d->connections->context); } +BusMatchmaker* +bus_connection_get_matchmaker (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return bus_context_get_matchmaker (d->connections->context); +} + /** * Checks whether the connection is registered with the message bus. * @@ -1024,6 +1083,62 @@ bus_connection_send_oom_error (DBusConnection *connection, d->oom_preallocated = NULL; } +void +bus_connection_add_match_rule_link (DBusConnection *connection, + DBusList *link) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_append_link (&d->match_rules, link); + + d->n_match_rules += 1; +} + +dbus_bool_t +bus_connection_add_match_rule (DBusConnection *connection, + BusMatchRule *rule) +{ + DBusList *link; + + link = _dbus_list_alloc_link (rule); + + if (link == NULL) + return FALSE; + + bus_connection_add_match_rule_link (connection, link); + + return TRUE; +} + +void +bus_connection_remove_match_rule (DBusConnection *connection, + BusMatchRule *rule) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_remove_last (&d->match_rules, rule); + + d->n_match_rules -= 1; + _dbus_assert (d->n_match_rules >= 0); +} + +int +bus_connection_get_n_match_rules (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + return d->n_match_rules; +} + void bus_connection_add_owned_service_link (DBusConnection *connection, DBusList *link) @@ -1092,6 +1207,8 @@ bus_connection_complete (DBusConnection *connection, _dbus_assert (d != NULL); _dbus_assert (d->name == NULL); _dbus_assert (d->policy == NULL); + + _dbus_assert (!bus_connection_is_active (connection)); if (!_dbus_string_copy_data (name, &d->name)) { @@ -1147,6 +1264,8 @@ bus_connection_complete (DBusConnection *connection, /* See if we can remove the timeout */ bus_connections_expire_incomplete (d->connections); + + _dbus_assert (bus_connection_is_active (connection)); return TRUE; } @@ -1327,7 +1446,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction, * eat it; the driver doesn't care about getting a reply. */ if (!bus_context_check_security_policy (bus_transaction_get_context (transaction), - NULL, connection, message, NULL)) + NULL, connection, connection, message, NULL)) return TRUE; return bus_transaction_send (transaction, connection, message); diff --git a/bus/connection.h b/bus/connection.h index 92c93267..d9fd727e 100644 --- a/bus/connection.h +++ b/bus/connection.h @@ -44,16 +44,18 @@ void bus_connections_foreach_active (BusConnections BusConnectionForeachFunction function, void *data); BusContext* bus_connections_get_context (BusConnections *connections); +void bus_connections_increment_stamp (BusConnections *connections); BusContext* bus_connection_get_context (DBusConnection *connection); BusConnections* bus_connection_get_connections (DBusConnection *connection); BusRegistry* bus_connection_get_registry (DBusConnection *connection); BusActivation* bus_connection_get_activation (DBusConnection *connection); +BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection); dbus_bool_t bus_connections_check_limits (BusConnections *connections, DBusConnection *requesting_completion, DBusError *error); void bus_connections_expire_incomplete (BusConnections *connections); - +dbus_bool_t bus_connection_mark_stamp (DBusConnection *connection); dbus_bool_t bus_connection_is_active (DBusConnection *connection); const char *bus_connection_get_name (DBusConnection *connection); @@ -62,6 +64,15 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection); void bus_connection_send_oom_error (DBusConnection *connection, DBusMessage *in_reply_to); +/* called by signals.c */ +dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection, + BusMatchRule *rule); +void bus_connection_add_match_rule_link (DBusConnection *connection, + DBusList *link); +void bus_connection_remove_match_rule (DBusConnection *connection, + BusMatchRule *rule); +int bus_connection_get_n_match_rules (DBusConnection *connection); + /* called by services.c */ dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection, diff --git a/bus/dbus-daemon-1.1.in b/bus/dbus-daemon-1.1.in index ec915edd..b272a62e 100644 --- a/bus/dbus-daemon-1.1.in +++ b/bus/dbus-daemon-1.1.in @@ -328,26 +328,32 @@ in the config file. .TP .I "" +.I "" + +.PP +A element appears below a element and prohibits some +action. The element makes an exception to previous +statements, and works just like but with the inverse meaning. .PP -A element appears below a element and prohibits -some action. The possible attributes of a element are: +The possible attributes of these elements are: .nf send_interface="interface_name" send_member="method_or_signal_name" send_error="error_name" - send_service="service_name" - send_type="method_call|method_return|signal|error" + send_destination="service_name" + send_type="method_call" | "method_return" | "signal" | "error" send_path="/path/name" receive_interface="interface_name" receive_member="method_or_signal_name" receive_error="error_name" - receive_service="service_name" - receive_type="method_call|method_return|signal|error" + receive_sender="service_name" + receive_type="method_call" | "method_return" | "signal" | "error" receive_path="/path/name" + + eavesdrop="true" | "false" - receive="messagename" own="servicename" user="username" group="groupname" @@ -359,8 +365,8 @@ Examples: - - + + .fi @@ -371,7 +377,7 @@ particular action. If it matches, the action is denied (unless later rules in the config file allow it). .PP -send_service and receive_service rules mean that messages may not be +send_destination and receive_sender rules mean that messages may not be sent to or received from the *owner* of the given service, not that they may not be sent *to that service name*. That is, if a connection owns services A, B, C, and sending to A is denied, sending to B or C @@ -381,6 +387,22 @@ will not work either. The other send_* and receive_* attributes are purely textual/by-value matches against the given field in the message header. +.PP +"Eavesdropping" occurs when an application receives a message that +was explicitly addressed to a service the application does not own. +Eavesdropping thus only applies to messages that are addressed to +services (i.e. it does not apply to signals). + +.PP +For , eavesdrop="true" indicates that the rule matches even +when eavesdropping. eavesdrop="false" is the default and means that +the rule only allows messages to go to their specified recipient. +For , eavesdrop="true" indicates that the rule matches +only when eavesdropping. eavesdrop="false" is the default for +also, but here it means that the rule applies always, even when +not eavesdropping. The eavesdrop attribute can only be combined with +receive rules (with receive_* attributes). + .PP user and group denials mean that the given user or group may not connect to the message bus. @@ -413,13 +435,6 @@ received" are evaluated separately. Be careful with send_interface/receive_interface, because the interface field in messages is optional. -.TP -.I "" - -.PP -Makes an exception to previous statements. Works -just like but with the inverse meaning. - .SH AUTHOR See http://www.freedesktop.org/software/dbus/doc/AUTHORS diff --git a/bus/dispatch.c b/bus/dispatch.c index 7bdda0d4..606c68ef 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -28,36 +28,33 @@ #include "services.h" #include "utils.h" #include "bus.h" +#include "signals.h" #include "test.h" #include #include -typedef struct -{ - BusContext *context; - DBusConnection *sender; - DBusMessage *message; - BusTransaction *transaction; - DBusError *error; -} SendMessageData; - static dbus_bool_t -send_one_message (DBusConnection *connection, void *data) +send_one_message (DBusConnection *connection, + BusContext *context, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + BusTransaction *transaction, + DBusError *error) { - SendMessageData *d = data; - - if (!bus_context_check_security_policy (d->context, - d->sender, + if (!bus_context_check_security_policy (context, + sender, + addressed_recipient, connection, - d->message, + message, NULL)) return TRUE; /* silently don't send it */ - if (!bus_transaction_send (d->transaction, + if (!bus_transaction_send (transaction, connection, - d->message)) + message)) { - BUS_SET_OOM (d->error); + BUS_SET_OOM (error); return FALSE; } @@ -65,30 +62,60 @@ send_one_message (DBusConnection *connection, void *data) } dbus_bool_t -bus_dispatch_broadcast_message (BusTransaction *transaction, - DBusConnection *sender, - DBusMessage *message, - DBusError *error) +bus_dispatch_matches (BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + DBusError *error) { DBusError tmp_error; - SendMessageData d; BusConnections *connections; + DBusList *recipients; + BusMatchmaker *matchmaker; + DBusList *link; + BusContext *context; _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + + /* sender and recipient can both be NULL for the bus driver, + * or for signals with no particular recipient + */ + + _dbus_assert (sender == NULL || bus_connection_is_active (sender)); _dbus_assert (dbus_message_get_sender (message) != NULL); connections = bus_transaction_get_connections (transaction); dbus_error_init (&tmp_error); - d.sender = sender; - d.context = bus_transaction_get_context (transaction); - d.message = message; - d.transaction = transaction; - d.error = &tmp_error; - - bus_connections_foreach_active (connections, send_one_message, &d); + context = bus_transaction_get_context (transaction); + matchmaker = bus_context_get_matchmaker (context); + + recipients = NULL; + if (!bus_matchmaker_get_recipients (matchmaker, + bus_context_get_connections (context), + sender, addressed_recipient, message, + &recipients)) + { + BUS_SET_OOM (error); + return FALSE; + } + + link = _dbus_list_get_first_link (&recipients); + while (link != NULL) + { + DBusConnection *dest; + + dest = link->data; + + if (!send_one_message (dest, context, sender, addressed_recipient, + message, transaction, &tmp_error)) + break; + + link = _dbus_list_get_next_link (&recipients, link); + } + _dbus_list_clear (&recipients); + if (dbus_error_is_set (&tmp_error)) { dbus_move_error (&tmp_error, error); @@ -107,10 +134,12 @@ bus_dispatch (DBusConnection *connection, BusTransaction *transaction; BusContext *context; DBusHandlerResult result; - + DBusConnection *addressed_recipient; + result = DBUS_HANDLER_RESULT_HANDLED; transaction = NULL; + addressed_recipient = NULL; dbus_error_init (&error); context = bus_connection_get_context (connection); @@ -143,26 +172,31 @@ bus_dispatch (DBusConnection *connection, } #endif /* DBUS_ENABLE_VERBOSE_MODE */ - /* If service_name is NULL, this is a message to the bus daemon, not - * intended to actually go "on the bus"; e.g. a peer-to-peer + /* If service_name is NULL, if it's a signal we send it to all + * connections with a match rule. If it's not a signal, it goes to + * the bus daemon but doesn't go "on the bus"; e.g. a peer-to-peer * ping. Handle these immediately, especially disconnection * messages. There are no security policy checks on these. */ if (service_name == NULL) - { + { if (dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected")) - bus_connection_disconnected (connection); + { + bus_connection_disconnected (connection); + goto out; + } - /* DBusConnection also handles some of these automatically, we leave - * it to do so. - */ - result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - goto out; + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL) + { + /* DBusConnection also handles some of these automatically, we leave + * it to do so. + */ + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto out; + } } - - _dbus_assert (service_name != NULL); /* this message is intended for bus routing */ /* Create our transaction */ transaction = bus_transaction_new (context); @@ -191,11 +225,12 @@ bus_dispatch (DBusConnection *connection, */ service_name = dbus_message_get_destination (message); } - - if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */ + + if (service_name && + strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */ { if (!bus_context_check_security_policy (context, - connection, NULL, message, &error)) + connection, NULL, NULL, message, &error)) { _dbus_verbose ("Security policy rejected message\n"); goto out; @@ -209,22 +244,16 @@ bus_dispatch (DBusConnection *connection, { _dbus_verbose ("Received message from non-registered client. Disconnecting.\n"); dbus_connection_disconnect (connection); + goto out; } - /* FIXME what if we un-special-case this service and just have a flag - * on services that all service owners will get messages to it, not just - * the primary owner. - */ - else if (strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST) == 0) /* spam! */ - { - if (!bus_dispatch_broadcast_message (transaction, connection, message, &error)) - goto out; - } - else /* route to named service */ + else if (service_name != NULL) /* route to named service */ { DBusString service_string; BusService *service; BusRegistry *registry; + _dbus_assert (service_name != NULL); + registry = bus_connection_get_registry (connection); _dbus_string_init_const (&service_string, service_name); @@ -239,24 +268,30 @@ bus_dispatch (DBusConnection *connection, goto out; } else - { - DBusConnection *recipient; - - recipient = bus_service_get_primary_owner (service); - _dbus_assert (recipient != NULL); + { + addressed_recipient = bus_service_get_primary_owner (service); + _dbus_assert (addressed_recipient != NULL); if (!bus_context_check_security_policy (context, - connection, recipient, message, &error)) + connection, addressed_recipient, + addressed_recipient, + message, &error)) goto out; /* Dispatch the message */ - if (!bus_transaction_send (transaction, recipient, message)) + if (!bus_transaction_send (transaction, addressed_recipient, message)) { BUS_SET_OOM (&error); goto out; } } } + + /* Now match the messages against any match rules, which will send + * out signals and such. addressed_recipient may == NULL. + */ + if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error)) + goto out; out: if (dbus_error_is_set (&error)) @@ -673,7 +708,7 @@ check_hello_message (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; char *name; @@ -684,6 +719,8 @@ check_hello_message (BusContext *context, name = NULL; acquired = NULL; message = NULL; + + _dbus_verbose ("check_hello_message for %p\n", connection); message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, DBUS_PATH_ORG_FREEDESKTOP_DBUS, @@ -791,7 +828,7 @@ check_hello_message (BusContext *context, while (!dbus_bus_set_base_service (connection, name)) _dbus_wait_for_memory (); - scd.skip_connection = NULL; + scd.skip_connection = connection; /* we haven't done AddMatch so won't get it ourselves */ scd.failed = FALSE; scd.expected_service_name = name; bus_test_clients_foreach (check_service_created_foreach, @@ -857,6 +894,126 @@ check_hello_message (BusContext *context, return retval; } +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_add_match_all (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_bool_t retval; + dbus_uint32_t serial; + DBusError error; + + retval = FALSE; + dbus_error_init (&error); + message = NULL; + + _dbus_verbose ("check_add_match_all for %p\n", connection); + + message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, + DBUS_PATH_ORG_FREEDESKTOP_DBUS, + DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS, + "AddMatch"); + + if (message == NULL) + return TRUE; + + if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "", /* FIXME */ + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + /* send our message */ + bus_test_run_clients_loop (TRUE); + + dbus_connection_ref (connection); /* because we may get disconnected */ + block_connection_until_message_from_bus (context, connection); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected\n"); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "AddMatch", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + ; /* good, expected */ + _dbus_assert (dbus_message_get_reply_serial (message) == serial); + } + else + { + warn_unexpected (connection, message, "method return for AddMatch"); + + goto out; + } + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return retval; +} + /* returns TRUE if the correct thing happens, * but the correct thing may include OOM errors. */ @@ -885,7 +1042,7 @@ check_hello_connection (BusContext *context) if (!check_hello_message (context, connection)) return FALSE; - + if (dbus_bus_get_base_service (connection) == NULL) { /* We didn't successfully register, so we can't @@ -895,6 +1052,9 @@ check_hello_connection (BusContext *context) } else { + if (!check_add_match_all (context, connection)) + return FALSE; + kill_client_connection (context, connection); } @@ -911,7 +1071,7 @@ check_nonexistent_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; @@ -1293,7 +1453,7 @@ check_send_exit_to_service (BusContext *context, { dbus_bool_t got_error; DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; _dbus_verbose ("Sending exit message to the test service\n"); @@ -1462,7 +1622,7 @@ check_existent_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; char *base_service; @@ -1676,7 +1836,7 @@ check_segfault_service_activation (BusContext *context, DBusConnection *connection) { DBusMessage *message; - dbus_int32_t serial; + dbus_uint32_t serial; dbus_bool_t retval; DBusError error; @@ -1877,6 +2037,9 @@ bus_dispatch_test (const DBusString *test_data_dir) if (!check_hello_message (context, foo)) _dbus_assert_not_reached ("hello message failed"); + + if (!check_add_match_all (context, foo)) + _dbus_assert_not_reached ("AddMatch message failed"); bar = dbus_connection_open ("debug-pipe:name=test-server", &error); if (bar == NULL) @@ -1887,6 +2050,9 @@ bus_dispatch_test (const DBusString *test_data_dir) if (!check_hello_message (context, bar)) _dbus_assert_not_reached ("hello message failed"); + + if (!check_add_match_all (context, bar)) + _dbus_assert_not_reached ("AddMatch message failed"); baz = dbus_connection_open ("debug-pipe:name=test-server", &error); if (baz == NULL) @@ -1898,6 +2064,9 @@ bus_dispatch_test (const DBusString *test_data_dir) if (!check_hello_message (context, baz)) _dbus_assert_not_reached ("hello message failed"); + if (!check_add_match_all (context, baz)) + _dbus_assert_not_reached ("AddMatch message failed"); + if (!check_no_leftovers (context)) { _dbus_warn ("Messages were left over after setting up initial connections"); @@ -1954,6 +2123,9 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir) if (!check_hello_message (context, foo)) _dbus_assert_not_reached ("hello message failed"); + if (!check_add_match_all (context, foo)) + _dbus_assert_not_reached ("addmatch message failed"); + if (!check_no_leftovers (context)) { _dbus_warn ("Messages were left over after setting up initial SHA-1 connection\n"); diff --git a/bus/dispatch.h b/bus/dispatch.h index 18f74529..d8107b1a 100644 --- a/bus/dispatch.h +++ b/bus/dispatch.h @@ -29,8 +29,9 @@ dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection); void bus_dispatch_remove_connection (DBusConnection *connection); -dbus_bool_t bus_dispatch_broadcast_message (BusTransaction *transaction, +dbus_bool_t bus_dispatch_matches (BusTransaction *transaction, DBusConnection *sender, + DBusConnection *recipient, DBusMessage *message, DBusError *error); diff --git a/bus/driver.c b/bus/driver.c index 61bfe1c5..791fcd69 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -27,6 +27,7 @@ #include "driver.h" #include "dispatch.h" #include "services.h" +#include "signals.h" #include "utils.h" #include #include @@ -69,7 +70,7 @@ bus_driver_send_service_deleted (const char *service_name, return FALSE; } - retval = bus_dispatch_broadcast_message (transaction, NULL, message, error); + retval = bus_dispatch_matches (transaction, NULL, NULL, message, error); dbus_message_unref (message); return retval; @@ -111,7 +112,7 @@ bus_driver_send_service_created (const char *service_name, return FALSE; } - retval = bus_dispatch_broadcast_message (transaction, NULL, message, error); + retval = bus_dispatch_matches (transaction, NULL, NULL, message, error); dbus_message_unref (message); return retval; @@ -331,6 +332,7 @@ bus_driver_handle_hello (DBusConnection *connection, bus_service_set_prohibit_replacement (service, TRUE); + _dbus_assert (bus_connection_is_active (connection)); retval = TRUE; out_0: @@ -600,6 +602,160 @@ bus_driver_handle_activate_service (DBusConnection *connection, return retval; } +static dbus_bool_t +send_ack_reply (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + BUS_SET_OOM (error); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_unref (reply); + + return TRUE; +} + +static dbus_bool_t +bus_driver_handle_add_match (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusMatchRule *rule; + char *text; + DBusString str; + BusMatchmaker *matchmaker; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + text = NULL; + rule = NULL; + + if (bus_connection_get_n_match_rules (connection) >= + bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction))) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "Connection \"%s\" is not allowed to add more match rules " + "(increase limits in configuration file if required)", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)"); + goto failed; + } + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + _dbus_verbose ("No memory to get arguments to AddMatch\n"); + goto failed; + } + + _dbus_string_init_const (&str, text); + + rule = bus_match_rule_parse (connection, &str, error); + if (rule == NULL) + goto failed; + + matchmaker = bus_connection_get_matchmaker (connection); + + if (!bus_matchmaker_add_rule (matchmaker, rule)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!send_ack_reply (connection, transaction, + message, error)) + { + bus_matchmaker_remove_rule (matchmaker, rule); + goto failed; + } + + bus_match_rule_unref (rule); + dbus_free (text); + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (rule) + bus_match_rule_unref (rule); + if (text) + dbus_free (text); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_remove_match (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusMatchRule *rule; + char *text; + DBusString str; + BusMatchmaker *matchmaker; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + text = NULL; + rule = NULL; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + _dbus_verbose ("No memory to get arguments to RemoveMatch\n"); + goto failed; + } + + _dbus_string_init_const (&str, text); + + rule = bus_match_rule_parse (connection, &str, error); + if (rule == NULL) + goto failed; + + /* Send the ack before we remove the rule, since the ack is undone + * on transaction cancel, but rule removal isn't. + */ + if (!send_ack_reply (connection, transaction, + message, error)) + goto failed; + + matchmaker = bus_connection_get_matchmaker (connection); + + if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error)) + goto failed; + + bus_match_rule_unref (rule); + dbus_free (text); + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (rule) + bus_match_rule_unref (rule); + if (text) + dbus_free (text); + return FALSE; +} + /* For speed it might be useful to sort this in order of * frequency of use (but doesn't matter with only a few items * anyhow) @@ -616,7 +772,9 @@ struct { "ActivateService", bus_driver_handle_activate_service }, { "Hello", bus_driver_handle_hello }, { "ServiceExists", bus_driver_handle_service_exists }, - { "ListServices", bus_driver_handle_list_services } + { "ListServices", bus_driver_handle_list_services }, + { "AddMatch", bus_driver_handle_add_match }, + { "RemoveMatch", bus_driver_handle_remove_match } }; dbus_bool_t diff --git a/bus/policy.c b/bus/policy.c index 21d0b02e..2d462fb6 100644 --- a/bus/policy.c +++ b/bus/policy.c @@ -917,16 +917,33 @@ dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy, BusRegistry *registry, DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, DBusMessage *message) { DBusList *link; dbus_bool_t allowed; + dbus_bool_t eavesdropping; + + /* NULL sender, proposed_recipient means the bus driver. NULL + * addressed_recipient means the message didn't specify an explicit + * target. If proposed_recipient is NULL, then addressed_recipient + * is also NULL but is implicitly the bus driver. + */ + + _dbus_assert (proposed_recipient == NULL || + (dbus_message_get_destination (message) == NULL || + addressed_recipient != NULL)); + + eavesdropping = + (proposed_recipient == NULL || /* explicitly to bus driver */ + (addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */ /* policy->rules is in the order the rules appeared * in the config file, i.e. last rule that applies wins */ - _dbus_verbose (" (policy) checking receive rules\n"); + _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping); allowed = FALSE; link = _dbus_list_get_first_link (&policy->rules); @@ -950,6 +967,24 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, continue; } } + + /* for allow, eavesdrop=false means the rule doesn't apply when + * eavesdropping. eavesdrop=true means always allow. + */ + if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n"); + continue; + } + + /* for deny, eavesdrop=true means the rule applies only when + * eavesdropping; eavesdrop=false means always deny. + */ + if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n"); + continue; + } if (rule->d.receive.path != NULL) { @@ -1036,7 +1071,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy, } } } - + /* Use this rule */ allowed = rule->allow; diff --git a/bus/policy.h b/bus/policy.h index 5824816c..63981cc0 100644 --- a/bus/policy.h +++ b/bus/policy.h @@ -74,6 +74,7 @@ struct BusPolicyRule char *member; char *error; char *origin; + unsigned int eavesdrop : 1; } receive; struct @@ -134,6 +135,8 @@ dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy, dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy, BusRegistry *registry, DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, DBusMessage *message); dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy, DBusConnection *connection, diff --git a/bus/session.conf.in b/bus/session.conf.in index 09dd250e..45945688 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -14,10 +14,9 @@ - - + - + - - + + - + diff --git a/tools/dbus-send.c b/tools/dbus-send.c index 67abe066..06a87adb 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -44,7 +44,7 @@ main (int argc, char *argv[]) DBusMessageIter iter; int i; DBusBusType type = DBUS_BUS_SESSION; - const char *dest = DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST; + const char *dest = NULL; const char *name = NULL; const char *path = NULL; int message_type = DBUS_MESSAGE_TYPE_SIGNAL; -- cgit v1.2.1 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 --- ChangeLog | 10 ++++++++++ dbus/dbus-bus.c | 6 ++++++ dbus/dbus-connection.c | 38 ++++++++++++++++++++++++++++++++++++++ dbus/dbus-connection.h | 4 +++- 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 68dfde4d..1431a96c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +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 + 2003-09-21 Havoc Pennington Get matching rules mostly working in the bus; only actually 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 v1.2.1 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. --- ChangeLog | 12 ++++++ dbus/dbus-bus.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++- dbus/dbus-bus.h | 7 +++ doc/TODO | 3 ++ glib/dbus-glib.h | 25 +++++------ glib/dbus-gproxy.c | 94 ++++++++++++++++++++++++++++++++++++++--- glib/dbus-gproxy.h | 78 ---------------------------------- 7 files changed, 244 insertions(+), 97 deletions(-) delete mode 100644 glib/dbus-gproxy.h diff --git a/ChangeLog b/ChangeLog index 1431a96c..d0c88df3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +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. + 2003-09-21 Havoc Pennington * dbus/dbus-bus.c (dbus_bus_get): set exit_on_disconnect to TRUE 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 */ diff --git a/doc/TODO b/doc/TODO index 81862331..1935ff9f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -92,3 +92,6 @@ - Header fields names are required to be aligned on a 4 byte boundary at the moment. No alignment should be neccessary. + + - dbus_gproxy or dbus_g_proxy? + diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 63d34485..7fd88e71 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -88,18 +88,19 @@ void dbus_connection_register_g_object (DBusConnection *connection, typedef struct DBusGProxy DBusGProxy; -DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, - const char *service_name, - const char *interface_name); -DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, - const char *service_name, - const char *interface_name, - GError **error); -DBusGProxy* dbus_gproxy_new_for_object_path (DBusConnection *connection, - const char *path, - const char *interface_name); -DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, - const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, + const char *service_name, + const char *path_name, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, + const char *service_name, + const char *path_name, + const char *interface_name, + GError **error); +DBusGProxy* dbus_gproxy_new_for_peer (DBusConnection *connection, + const char *path_name, + const char *interface_name); + void dbus_gproxy_ref (DBusGProxy *proxy); void dbus_gproxy_unref (DBusGProxy *proxy); gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index b77e7d30..96a27888 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -28,6 +28,83 @@ * @{ */ +/** + * DBusGProxyManager's primary task is to route signals to the proxies + * those signals are emitted on. In order to do this it also has to + * track the owners of the services proxies are bound to. + */ +typedef struct +{ + GStaticMutex lock; /**< Thread lock */ + int refcount; /**< Reference count */ + + + +} DBusGProxyManager; + + +/** Lock the DBusGProxyManager */ +#define LOCK_MANAGER(mgr) (g_static_mutex_lock (&(mgr)->lock)) +/** Unlock the DBusGProxyManager */ +#define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock)) + +static DBusGProxyManager* +dbus_gproxy_manager_new (void) +{ + DBusGProxyManager *manager; + + manager = g_new0 (DBusGProxyManager, 1); + + manager->refcount = 1; + + g_static_mutex_init (&manager->lock); + + return manager; +} + +static void +dbus_gproxy_manager_ref (DBusGProxyManager *manager) +{ + g_assert (manager != NULL); + g_assert (manager->refcount > 0); + + LOCK_MANAGER (manager); + + manager->refcount += 1; + + UNLOCK_MANAGER (manager); +} + +static void +dbus_gproxy_manager_unref (DBusGProxyManager *manager) +{ + g_assert (manager != NULL); + g_assert (manager->refcount > 0); + + LOCK_MANAGER (manager); + manager->refcount -= 1; + if (manager->refcount == 0) + { + UNLOCK_MANAGER (manager); + + g_static_mutex_free (&manager->lock); + + g_free (manager); + } + else + { + UNLOCK_MANAGER (manager); + } +} + +static DBusGProxyManager* +dbus_gproxy_manager_get_for_connection (DBusConnection *connection) +{ + /* FIXME */ + + return NULL; +} + /** * Internals of DBusGProxy */ @@ -37,8 +114,8 @@ struct DBusGProxy int refcount; /**< Reference count */ DBusConnection *connection; /**< Connection to communicate over */ char *service; /**< Service messages go to or NULL */ - char *interface; /**< Interface messages go to or NULL */ char *path; /**< Path messages go to or NULL */ + char *interface; /**< Interface messages go to or NULL */ }; /** Lock the DBusGProxy */ @@ -82,23 +159,27 @@ _dbus_gproxy_new (DBusConnection *connection) * * @param connection the connection to the remote bus or app * @param service_name name of the service on the message bus + * @param path_name name of the object inside the service to call methods on * @param interface_name name of the interface to call methods on * @returns new proxy object */ DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, const char *service_name, + const char *path_name, const char *interface_name) { DBusGProxy *proxy; g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (path_name != NULL, NULL); g_return_val_if_fail (interface_name != NULL, NULL); proxy = _dbus_gproxy_new (connection); proxy->service = g_strdup (service_name); + proxy->path = g_strdup (path_name); proxy->interface = g_strdup (interface_name); return proxy; @@ -144,8 +225,9 @@ dbus_gproxy_unref (DBusGProxy *proxy) UNLOCK_PROXY (proxy); dbus_connection_unref (proxy->connection); - g_free (proxy->interface); g_free (proxy->service); + g_free (proxy->path); + g_free (proxy->interface); g_static_mutex_free (&proxy->lock); g_free (proxy); } @@ -316,14 +398,14 @@ dbus_gproxy_send (DBusGProxy *proxy, if (!dbus_message_set_destination (message, proxy->service)) g_error ("Out of memory"); } - if (proxy->interface) + if (proxy->path) { - if (!dbus_message_set_interface (message, proxy->interface)) + if (!dbus_message_set_path (message, proxy->path)) g_error ("Out of memory"); } - if (proxy->path) + if (proxy->interface) { - if (!dbus_message_set_path (message, proxy->path)) + if (!dbus_message_set_interface (message, proxy->interface)) g_error ("Out of memory"); } diff --git a/glib/dbus-gproxy.h b/glib/dbus-gproxy.h deleted file mode 100644 index 4e8f3f60..00000000 --- a/glib/dbus-gproxy.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-gproxy.h convenience routines for calling methods, etc. - * - * 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_GPROXY_H -#define DBUS_GPROXY_H - -#if !defined (DBUS_INSIDE_DBUS_GLIB_H) && !defined (DBUS_COMPILATION) -#error "Only can be included directly, this file may disappear or change contents." -#endif - -#include -#include -#include /* for GCallback at the moment, we don't link to it */ - -G_BEGIN_DECLS - -typedef struct DBusGProxy DBusGProxy; - -DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, - const char *service_name, - const char *interface_name); -DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, - const char *service_name, - const char *interface_name, - GError **error); -DBusGProxy* dbus_gproxy_new_for_object_path (DBusConnection *connection, - const char *path, - const char *interface_name); -DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection, - const char *interface_name); -void dbus_gproxy_ref (DBusGProxy *proxy); -void dbus_gproxy_unref (DBusGProxy *proxy); -gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, - const char *signal_name, - GCallback callback, - void *data, - GFreeFunc free_data_func, - GError **error); -DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, - ...); -gboolean dbus_gproxy_end_call (DBusGProxy *proxy, - DBusPendingCall *pending, - GError **error, - int first_arg_type, - ...); -void dbus_gproxy_oneway_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, - ...); -void dbus_gproxy_send (DBusGProxy *proxy, - DBusMessage *message, - dbus_uint32_t *client_serial); - - -G_END_DECLS - -#endif /* DBUS_GPROXY_H */ -- cgit v1.2.1 From f4cffc0e49d48a8dbf158230d7e816d8713566da Mon Sep 17 00:00:00 2001 From: Seth Nickell Date: Mon, 22 Sep 2003 05:45:59 +0000 Subject: 2003-09-21 Seth Nickell First checkin of the Python bindings. * python/.cvsignore: * python/Makefile.am: * python/dbus_bindings.pyx.in: * python/dbus_h_wrapper.h: Pieces for Pyrex to operate on, building a dbus_bindings.so python module for low-level access to the DBus APIs. * python/dbus.py: High-level Python module for accessing DBus objects. * configure.in: * Makefile.am: Build stuff for the python bindings. * acinclude.m4: Extra macro needed for finding the Python C header files. --- ChangeLog | 25 ++ Makefile.am | 5 +- acinclude.m4 | 26 ++ configure.in | 40 ++ python/.cvsignore | 8 + python/Makefile.am | 28 ++ python/dbus.py | 196 ++++++++++ python/dbus_bindings.pyx.in | 900 ++++++++++++++++++++++++++++++++++++++++++++ python/dbus_h_wrapper.h | 3 + python/extract.py | 237 ++++++++++++ test/test-service.c | 5 +- 11 files changed, 1471 insertions(+), 2 deletions(-) create mode 100644 python/.cvsignore create mode 100644 python/Makefile.am create mode 100644 python/dbus.py create mode 100644 python/dbus_bindings.pyx.in create mode 100644 python/dbus_h_wrapper.h create mode 100644 python/extract.py diff --git a/ChangeLog b/ChangeLog index d0c88df3..530c47c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2003-09-21 Seth Nickell + + First checkin of the Python bindings. + + * python/.cvsignore: + * python/Makefile.am: + * python/dbus_bindings.pyx.in: + * python/dbus_h_wrapper.h: + + Pieces for Pyrex to operate on, building a dbus_bindings.so + python module for low-level access to the DBus APIs. + + * python/dbus.py: + + High-level Python module for accessing DBus objects. + + * configure.in: + * Makefile.am: + + Build stuff for the python bindings. + + * acinclude.m4: + + Extra macro needed for finding the Python C header files. + 2003-09-21 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_new): start diff --git a/Makefile.am b/Makefile.am index 5bb5ae6a..47329972 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,8 +16,11 @@ if DBUS_USE_MCS MONO_SUBDIR=mono endif +if HAVE_PYTHON + PYTHON_SUBDIR=python +endif -SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) test tools +SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) $(PYTHON_SUBDIR) test tools pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = dbus-1.pc $(GLIB_PC) diff --git a/acinclude.m4 b/acinclude.m4 index c80e0acf..27da0a4c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -55,3 +55,29 @@ AC_DEFUN(PKG_CHECK_MODULES, [ ]) + +dnl a macro to check for ability to create python extensions +dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) +dnl function also defines PYTHON_INCLUDES +AC_DEFUN([AM_CHECK_PYTHON_HEADERS], +[AC_REQUIRE([AM_PATH_PYTHON]) +AC_MSG_CHECKING(for headers required to compile python extensions) +dnl deduce PYTHON_INCLUDES +py_prefix=`$PYTHON -c "import sys; print sys.prefix"` +py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` +PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" +if test "$py_prefix" != "$py_exec_prefix"; then + PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" +fi +AC_SUBST(PYTHON_INCLUDES) +dnl check if the headers exist: +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" +AC_TRY_CPP([#include ],dnl +[AC_MSG_RESULT(found) +$1],dnl +[AC_MSG_RESULT(not found) +$2]) +CPPFLAGS="$save_CPPFLAGS" +]) + diff --git a/configure.in b/configure.in index e81a8d6a..6cf4accb 100644 --- a/configure.in +++ b/configure.in @@ -35,6 +35,8 @@ AC_ARG_ENABLE(gcov, [ --enable-gcov compile with coverage p AC_ARG_ENABLE(abstract-sockets, [ --enable-abstract-sockets use abstract socket namespace (linux only)],enable_abstract_sockets=$enableval,enable_abstract_sockets=auto) AC_ARG_ENABLE(gcj, [ --enable-gcj build gcj bindings],enable_gcj=$enableval,enable_gcj=no) AC_ARG_ENABLE(mono, [ --enable-mono build mono bindings],enable_mono=$enableval,enable_mono=no) +AC_ARG_ENABLE(python, [ --enable-python build python bindings],enable_python=$enableval,enable_python=auto) + AC_ARG_WITH(xml, [ --with-xml=[libxml/expat] XML library to use]) AC_ARG_WITH(init-scripts, [ --with-init-scripts=[redhat] Style of init scripts to install]) @@ -834,6 +836,42 @@ fi AC_DEFINE_UNQUOTED(DBUS_SESSION_SOCKET_DIR, "$DBUS_SESSION_SOCKET_DIR", [Where per-session bus puts its sockets]) AC_SUBST(DBUS_SESSION_SOCKET_DIR) +# Detect if we can build Python bindings (need python, python headers, and pyrex) +if test x$enable_python = xno; then + have_python=no +else + AC_MSG_NOTICE([Checking to see if we can build Python bindings]) + have_python=no + AM_PATH_PYTHON(2.2) + + if test -z "$PYTHON" ; then + AC_MSG_WARN([Python not found]) + else + AC_CHECK_PROGS(PYREX, pyrexc) + + if test -z "$PYREX" ; then + have_pyrex=no + else + have_pyrex=yes + fi + + AM_CHECK_PYTHON_HEADERS(have_python_headers=yes,have_python_headers=no) + + if test x$have_pyrex = xyes -a x$have_python_headers = xyes ; then + have_python=yes + fi + fi + + if test x$have_python = xno ; then + if test x$enable_python = xyes ; then + AC_MSG_ERROR([Building python explicitly requested, but can't build python bindings]) + else + AC_MSG_WARN([Couldn't find either Pyrex or the Python headers, not building Python bindings]) + fi + fi +fi + +AM_CONDITIONAL(HAVE_PYTHON, test x$have_python = xyes) AC_OUTPUT([ @@ -846,6 +884,7 @@ bus/dbus-daemon-1.1 Makefile dbus/Makefile glib/Makefile +python/Makefile qt/Makefile gcj/Makefile gcj/org/Makefile @@ -914,6 +953,7 @@ echo " Building checks: ${enable_checks} Building Qt bindings: ${have_qt} Building GLib bindings: ${have_glib} + Building Python bindings: ${have_python} Building GTK+ tools: ${have_gtk} Building X11 code: ${enable_x11} Building documentation: ${enable_docs} diff --git a/python/.cvsignore b/python/.cvsignore new file mode 100644 index 00000000..8902bbe5 --- /dev/null +++ b/python/.cvsignore @@ -0,0 +1,8 @@ +*.pyc +*.pyo +Makefile +Makefile.in +build +*.la +*.lo +*.o \ No newline at end of file diff --git a/python/Makefile.am b/python/Makefile.am new file mode 100644 index 00000000..792dc477 --- /dev/null +++ b/python/Makefile.am @@ -0,0 +1,28 @@ +INCLUDES=-I$(top_builddir) -I$(top_builddir)/glib $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) $(PYTHON_INCLUDES) + +dbusdir = $(pythondir) +dbus_PYTHON = dbus.py + +dbusbindingsdir = $(pythondir) +dbusbindings_LTLIBRARIES = dbus_bindings.la + +dbus_bindings_la_LDFLAGS = -module -avoid-version -fPIC -export-symbols-regex initdbus_bindings +dbus_bindings_la_LIBADD = $(top_builddir)/dbus/libdbus-1.la $(top_builddir)/glib/libdbus-glib-1.la +dbus_bindings_la_SOURCES = dbus_bindings.c + +EXTRA_DIST = \ + dbus_bindings.pyx.in \ + extract.py \ + setup.py \ + test.py + +CLEANFILES = \ + dbus_bindings.pyx \ + dbus_bindings.c + + +dbus_bindings.pyx: dbus_bindings.pyx.in extract.py + -$(PYTHON) extract.py dbus_bindings.pyx.in -I$(top_builddir) > dbus_bindings.pyx + +dbus_bindings.c: dbus_bindings.pyx + -pyrexc dbus_bindings.pyx diff --git a/python/dbus.py b/python/dbus.py new file mode 100644 index 00000000..a7cca56a --- /dev/null +++ b/python/dbus.py @@ -0,0 +1,196 @@ + +"""Module for high-level communication over the FreeDesktop.org Bus (DBus) + +DBus allows you to share and access remote objects between processes +running on the desktop, and also to access system services (such as +the print spool). + +To use DBus, first get a Bus object, which provides a connection to one +of a few standard dbus-daemon instances that might be running. From the +Bus you can get a RemoteService. A service is provided by an application or +process connected to the Bus, and represents a set of objects. Once you +have a RemoteService you can get a RemoteObject that implements a specific interface +(an interface is just a standard group of member functions). Then you can call +those member functions directly. + +You can think of a complete method call as looking something like: + +Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org') + +This communicates over the SESSION Bus to the org.gnome.Evolution process to call the +Forward method of the /org/gnome/Evolution/Inbox object (which provides the +org.gnome.Evolution.MailFolder interface) with two string arguments. + +For example, the dbus-daemon itself provides a service and some objects: + +# Get a connection to the desktop-wide SESSION bus +bus = dbus.Bus(dbus.Bus.TYPE_SESSION) + +# Get the service provided by the dbus-daemon named org.freedesktop.DBus +dbus_service = bus.get_service('org.freedesktop.DBus') + +# Get a reference to the desktop bus' standard object, denoted +# by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus +# implements the 'org.freedesktop.DBus' interface +dbus_object = dbus_service.get_object('/org/freedesktop/DBus', + 'org.freedesktop.DBus') + +# One of the member functions in the org.freedesktop.DBus interface +# is ListServices(), which provides a list of all the other services +# registered on this bus. Call it, and print the list. +print(dbus_object.ListServices()) +""" + +import dbus_bindings + +class Bus: + """A connection to a DBus daemon. + + One of three possible standard buses, the SESSION, SYSTEM, + or ACTIVATION bus + """ + TYPE_SESSION = dbus_bindings.BUS_SESSION + TYPE_SYSTEM = dbus_bindings.BUS_SYSTEM + TYPE_ACTIVATION = dbus_bindings.BUS_ACTIVATION + + def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True): + self._connection = dbus_bindings.bus_get(bus_type) + + if (glib_mainloop): + self._connection.setup_with_g_main() + + def get_service(self, service_name="org.freedesktop.Broadcast"): + """Get one of the RemoteServices connected to this Bus. service_name + is just a string of the form 'com.widgetcorp.MyService' + """ + return RemoteService(self._connection, service_name) + + def get_connection(self): + """Get the dbus_bindings.Connection object associated with this Bus""" + return self._connection + + +class RemoteObject: + """A remote Object. + + A RemoteObject is provided by a RemoteService on a particular Bus. RemoteObjects + have member functions, and can be called like normal Python objects. + """ + def __init__(self, connection, service_name, object_path, interface): + self._connection = connection + self._service_name = service_name + self._object_path = object_path + self._interface = interface + + def __getattr__(self, member): + if member == '__call__': + return object.__call__ + else: + return RemoteMethod(self._connection, self._service_name, + self._object_path, self._interface, member) + + +class RemoteMethod: + """A remote Method. + + Typically a member of a RemoteObject. Calls to the + method produce messages that travel over the Bus and are routed + to a specific Service. + """ + def __init__(self, connection, service_name, object_path, interface, method_name): + self._connection = connection + self._service_name = service_name + self._object_path = object_path + self._interface = interface + self._method_name = method_name + + def __call__(self, *args): + print ("Going to call object(%s).interface(%s).method(%s)" + % (self._object_path, self._interface, self._method_name)) + + message = dbus_bindings.MethodCall(self._object_path, self._interface, self._method_name) + message.set_destination(self._service_name) + + # Add the arguments to the function + iter = message.get_iter() + for arg in args: + print ("Adding arg %s" % (arg)) + print ("Append success is %d" % (iter.append(arg))) + print ("Args now %s" % (message.get_args_list())) + + reply_message = self._connection.send_with_reply_and_block(message, 5000) + + args_tuple = reply_message.get_args_list() + if (len(args_tuple) == 0): + return + elif (len(args_tuple) == 1): + return args_tuple[0] + else: + return args_tuple + +class Service: + """A base class for exporting your own Services across the Bus + + Just inherit from Service, providing the name of your service + (e.g. org.designfu.SampleService). + """ + def __init__(self, service_name, bus=None): + self._service_name = service_name + + if bus == None: + # Get the default bus + self._bus = Bus() + else: + self._bus = bus + + dbus_bindings.bus_acquire_service(self._bus.get_connection(), service_name) + + def get_bus(self): + """Get the Bus this Service is on""" + return self._bus + +class Object: + """A base class for exporting your own Objects across the Bus. + + Just inherit from Object and provide a list of methods to share + across the Bus. These will appear as member functions of your + ServiceObject. + """ + def __init__(self, object_path, methods_to_share, service): + self._object_path = object_path + self._service = service + self._object_methods = methods_to_share + self._bus = service.get_bus() + self._connection = self._bus.get_connection() + + self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb) + + def _unregister_cb(self, connection): + print ("Unregister") + + def message_cb(self, connection, message): + print ("Message %s received" % (message)) + print ("MethodCall %s" % (message.get_member())) + +class RemoteService: + """A remote service providing objects. + + A service is typically a process or application that provides + remote objects, but can also be the broadcast service that + receives signals from all applications on the Bus. + """ + + def __init__(self, connection, service_name): + self._connection = connection + self._service_name = service_name + + def get_object(self, object_path, interface): + """Get an object provided by this Service that implements a + particular interface. object_path is a string of the form + '/com/widgetcorp/MyService/MyObject1'. interface looks a lot + like a service_name (they're often the same) and is of the form, + 'com.widgetcorp.MyInterface', and mostly just defines the + set of member functions that will be present in the object. + """ + return RemoteObject(self._connection, self._service_name, object_path, interface) + diff --git a/python/dbus_bindings.pyx.in b/python/dbus_bindings.pyx.in new file mode 100644 index 00000000..2e575edc --- /dev/null +++ b/python/dbus_bindings.pyx.in @@ -0,0 +1,900 @@ +# -*- Mode: Python -*- + +#include "dbus_h_wrapper.h" + +cdef extern from "stdlib.h": + cdef void *malloc(size_t size) + cdef void free(void *ptr) + +cdef extern from "dbus-glib.h": + ctypedef struct GMainContext + cdef void dbus_connection_setup_with_g_main (DBusConnection *connection, + GMainContext *context) + cdef void dbus_server_setup_with_g_main (DBusServer *server, + GMainContext *context) + +cdef extern from "Python.h": + void Py_XINCREF (object) + void Py_XDECREF (object) + + +ctypedef struct DBusError: + char *name + char *message + unsigned int dummy1 + unsigned int dummy2 + unsigned int dummy3 + unsigned int dummy4 + unsigned int dummy5 + void *padding1 + +ctypedef 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 + +ctypedef struct DBusObjectPathVTable: + DBusObjectPathUnregisterFunction unregister_function + DBusObjectPathMessageFunction message_function + void (* dbus_internal_pad1) (void *) + void (* dbus_internal_pad2) (void *) + void (* dbus_internal_pad3) (void *) + void (* dbus_internal_pad4) (void *) + + +class DBusException(Exception): + pass + +class ConnectionError(Exception): + pass + +cdef void cunregister_function_handler (DBusConnection *connection, + void *user_data): + print ("cunregister_function_handler() called") + tup = user_data + function = tup[0] + args = [Connection(_conn=connection)] + function(*args) + +cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection, + DBusMessage *msg, + void *user_data): + print ("cmessage_function_handler() called") + tup = user_data + print (tup) + function = tup[1] + message = Message(_create=0) + message._set_msg(msg) + args = [Connection(_conn=connection), + message] + retval = function(*args) + if (retval == None): + retval = DBUS_HANDLER_RESULT_HANDLED + return retval + +cdef DBusHandlerResult chandle_message_function_handler (DBusConnection *connection, + DBusMessage *msg, + void *user_data): + function = user_data + messagein = Message(_create=0) + messagein._set_msg(msg) + args = [Connection(_conn=connection), + messagein] + retval = function(*args) + if (retval == None): + retval = DBUS_HANDLER_RESULT_HANDLED + return retval + +cdef class Connection: + cdef DBusConnection *conn + + # FIXME: this is a major major hack. We use this because casting values to + # python objects and returning seemed to be corrupting them. This is a "global variable" :-( + cdef char **_parsed_path + + def __init__(self, address=None, _conn=None): + cdef DBusError error + dbus_error_init(&error) + if _conn != NULL: + self.conn = _conn + dbus_connection_ref(self.conn) + else: + self.conn = dbus_connection_open(address, + &error) + if dbus_error_is_set(&error): + raise DBusException, error.message + + dbus_connection_ref(self.conn) + + def _set_conn(self, conn): + self.conn = conn + + def _get_conn(self): + return self.conn + + #FIXME: this is totally busted, don't use a class shared member like parsed_path + def _build_parsed_path(self, path_element_list): + cdef char **cpatharray + size = len(path_element_list) + cpatharray = malloc(sizeof(char*) * (size + 1)) + + for i in range(size): + path_element = path_element_list[i] + cpatharray[i] = path_element + + cpatharray[size] = NULL + + self._parsed_path = cpatharray + + def get_base_service(self): + return bus_get_base_service(self) + + def setup_with_g_main(self): + dbus_connection_setup_with_g_main(self.conn, NULL) + + def disconnect(self): + dbus_connection_disconnect(self.conn) + + def get_is_connected(self): + return dbus_connection_get_is_connected(self.conn) + + def get_is_authenticated(self): + return dbus_connection_get_is_authenticated(self.conn) + + def flush(self): + dbus_connection_flush(self.conn) + + def borrow_message(self): + m = Message(_create=0) + m._set_msg(dbus_connection_borrow_message(self.conn)) + return m + + def return_message(self, message): + msg = message._get_msg() + dbus_connection_return_message(self.conn, msg) + + def steal_borrowed_message(self, message): + msg = message._get_msg() + dbus_connection_steal_borrowed_message(self.conn, + msg) + + def pop_message(self): + cdef DBusMessage *msg + msg = dbus_connection_pop_message(self.conn) + if msg != NULL: + m = Message(_create=0) + m._set_msg(msg) + else: + m = None + return m + + def get_dispatch_status(self): + return dbus_connection_get_dispatch_status(self.conn) + + def dispatch(self): + return dbus_connection_dispatch(self.conn) + + def send(self, message): + #cdef dbus_uint32_t client_serial + #if type(message) != Message: + # raise TypeError + + msg = message._get_msg() + retval = dbus_connection_send(self.conn, + msg, + NULL) + return retval + + def send_with_reply(self, message, timeout_milliseconds): + cdef dbus_bool_t retval + cdef DBusPendingCall *cpending_call + cdef DBusError error + dbus_error_init(&error) + + cpending_call = NULL + + msg = message._get_msg() + + retval = dbus_connection_send_with_reply(self.conn, + msg, + &cpending_call, + timeout_milliseconds) + + if dbus_error_is_set(&error): + raise DBusException, error.message + + if (cpending_call != NULL): + pending_call = PendingCall(cpending_call) + else: + pending_call = None + + return (retval, pending_call) + + def send_with_reply_and_block(self, message, + timeout_milliseconds=0): + cdef DBusMessage * retval + cdef DBusError error + dbus_error_init(&error) + + msg = message._get_msg() + + print ("About to block") + + retval = dbus_connection_send_with_reply_and_block( + self.conn, + msg, + timeout_milliseconds, + &error) + + print ("done") + + if dbus_error_is_set(&error): + raise DBusException, error.message + + if retval == NULL: + raise AssertionError + + m = Message(_create=0) + m._set_msg(retval) + return m + + def set_watch_functions(self, add_function, remove_function, data): + pass + + def set_timeout_functions(self, add_function, remove_function, data): + pass + + def set_wakeup_main_function(self, wakeup_main_function, data): + pass + + # FIXME: set_dispatch_status_function, get_unix_user, set_unix_user_function + + def add_filter(self, function): + return dbus_connection_add_filter(self.conn, + chandle_message_function_handler, + function, + NULL) + + + #FIXME: remove_filter + # this is pretty tricky, we want to only remove the filter + # if we truly have no more calls to our message_function_handler...ugh + + def set_data(self, slot, data): + pass + + def get_data(self, slot): + pass + + def set_max_message_size(self, size): + dbus_connection_set_max_message_size(self.conn, size) + + def get_max_message_size(self): + return dbus_connection_get_max_message_size(self.conn) + + def set_max_received_size(self, size): + dbus_connection_set_max_received_size(self.conn, size) + + def get_max_received_size(self): + return dbus_connection_get_max_received_size(self.conn) + + def get_outgoing_size(self): + return dbus_connection_get_outgoing_size(self.conn) + + # preallocate_send, free_preallocated_send, send_preallocated + + def register_object_path(self, path, unregister_cb, message_cb): + cdef DBusObjectPathVTable cvtable + + cvtable.unregister_function = cunregister_function_handler + cvtable.message_function = cmessage_function_handler + + user_data = [unregister_cb, message_cb] + #Py_XINCREF(user_data) + + path_element_list = path[1:].split('/') + self._build_parsed_path(path_element_list) + + return dbus_connection_register_object_path(self.conn, self._parsed_path, &cvtable, + user_data) + + def register_fallback(self, path, unregister_cb, message_cb): + cdef DBusObjectPathVTable cvtable + + cvtable.unregister_function = cunregister_function_handler + cvtable.message_function = cmessage_function_handler + + user_data = [unregister_cb, message_cb] + Py_XINCREF(user_data) + + print ("Ref inced") + + path_element_list = path[1:].split('/') + self._build_parsed_path(path_element_list) + + return dbus_connection_register_fallback(self.conn, self._parsed_path, &cvtable, + user_data) + + #FIXME: unregister_object_path , see problems with remove_filter + + def list_registered (self, parent_path): + cdef char **cchild_entries + cdef dbus_bool_t retval + + path_element_list = parent_path[1:].split('/') + self._build_parsed_path(path_element_list) + + retval = dbus_connection_list_registered(self.conn, self._parsed_path, &cchild_entries) + + if (not retval): + #FIXME: raise out of memory exception? + return None + + i = 0 + child_entries = [] + print ("cchild_entries[0] is %d" % (cchild_entries[0])) + while (cchild_entries[i] != NULL): + child_entries.append(cchild_entries[i]) + i = i + 1 + + dbus_free_string_array(cchild_entries) + + return child_entries + + +cdef class PendingCall: + cdef DBusPendingCall *pending_call + + def __init__(self, _pending_call): + self.pending_call = _pending_call + dbus_pending_call_ref(self.pending_call) + + def _get_pending_call(self): + return self.pending_call + + def cancel(self): + dbus_pending_call_cancel(self.pending_call) + + def get_completed(self): + return dbus_pending_call_get_completed(self.pending_call) + + def get_reply(self): + message = Message(_create=0) + message._set_msg(dbus_pending_call_get_reply(self.pending_call)) + return message + + def block(self): + dbus_pending_call_block(self.pending_call) + +cdef class Watch: + cdef DBusWatch* watch + def __init__(self, cwatch): + self.watch = cwatch + + def get_fd(self): + return dbus_watch_get_fd(self.watch) + + # FIXME: not picked up correctly by extract.py + #def get_flags(self): + # return dbus_watch_get_flags(self.watch) + + def handle(self, flags): + return dbus_watch_handle(self.watch, flags) + + def get_enabled(self): + return dbus_watch_get_enabled(self.watch) + +cdef class MessageIter: + cdef DBusMessageIter *iter + cdef DBusMessageIter real_iter + + + def __init__(self, message): + self.iter = &self.real_iter + msg = message._get_msg() + dbus_message_iter_init(msg, self.iter) + + def get_iter(self): + return self.iter + + def has_next(self): + return dbus_message_iter_has_next(self.iter) + + def next(self): + return dbus_message_iter_next(self.iter) + + def get(self): + arg_type = self.get_arg_type() + + if arg_type == TYPE_INVALID: + raise TypeError, 'Invalid arg type in MessageIter' + elif arg_type == TYPE_STRING: + retval = self.get_string() + elif arg_type == TYPE_INT32: + retval = self.get_int32() + elif arg_type == TYPE_UINT32: + retval = self.get_uint32() + elif arg_type == TYPE_DOUBLE: + retval = self.get_double() + elif arg_type == TYPE_BYTE: + retval = self.get_byte() + elif arg_type == TYPE_BOOLEAN: + retval = self.get_boolean() + elif arg_type == TYPE_ARRAY: + array_type = self.get_array_type() + + if array_type == TYPE_STRING: + retval = self.get_string_array() + elif array_type == TYPE_BOOLEAN: + retval = self.get_boolean_array() + else: + raise TypeError, "Unknown array type %d in MessageIter" % (array_type) + else: + raise TypeError, 'Unknown arg type %d in MessageIter' % (argtype) + + return retval + + def get_arg_type(self): + return dbus_message_iter_get_arg_type(self.iter) + + def get_array_type(self): + return dbus_message_iter_get_array_type(self.iter) + + #FIXME: implement get_byte + #def get_byte(self): + # return dbus_message_iter_get_byte(self.iter) + + def get_boolean(self): + return dbus_message_iter_get_boolean(self.iter) + + def get_int32(self): + return dbus_message_iter_get_int32(self.iter) + + def get_uint32(self): + return dbus_message_iter_get_uint32(self.iter) + + def get_double(self): + return dbus_message_iter_get_double(self.iter) + + def get_string(self): + return dbus_message_iter_get_string(self.iter) + + def get_dict_key(self): + return dbus_message_iter_get_dict_key(self.iter) + + # FIXME: implement dbus_message_iter_get_named + # dbus_message_iter_init_array_iterator + + def get_byte_array(self): + cdef int len + cdef unsigned char *retval + dbus_message_iter_get_byte_array(self.iter, &retval, &len) + list = [] + for i from 0 <= i < len: + list.append(chr(retval[i])) + return list + + # FIXME: implement dbus_message_iter_get_boolean_array + # dbus_message_iter_get_int32_array + # dbus_message_iter_get_uint32_array + # dbus_message_iter_get_double_array + + def get_string_array(self): + cdef int len + cdef char **retval + + dbus_message_iter_get_string_array(self.iter, &retval, &len) + list = [] + for i from 0 <= i < len: + list.append(retval[i]) + return list + + # dbus_message_append_iter_init included in class Message + + #FIXME: handle all the different types? + def append(self, value): + value_type = type(value) + + if value_type == bool: + retval = self.append_boolean(value) + elif value_type == int: + retval = self.append_int32(value) + elif value_type == float: + retval = self.append_double(value) + elif value_type == str: + retval = self.append_string(value) + elif value_type == list: + if (len(list) == 1): + raise TypeError, "Empty list" + list_type = type(list[0]) + if list_type == str: + self.append_string_array(list) + else: + raise TypeError, "List of unknown type '%s'" % (list_type) + else: + raise TypeError, "Argument of unknown type '%s'" % (value_type) + + return retval + + def append_nil(self): + return dbus_message_iter_append_nil(self.iter) + + def append_boolean(self, value): + return dbus_message_iter_append_boolean(self.iter, value) + + def append_byte(self, value): + return dbus_message_iter_append_byte(self.iter, value) + + def append_int32(self, value): + return dbus_message_iter_append_int32(self.iter, value) + + def append_uint32(self, value): + return dbus_message_iter_append_uint32(self.iter, value) + + def append_double(self, value): + return dbus_message_iter_append_double(self.iter, value) + + def append_string(self, value): + return dbus_message_iter_append_string(self.iter, value) + + # FIXME: dbus_message_iter_append_named + + def append_dict_key(self, value): + return dbus_message_iter_append_dict_key(self.iter, value) + + # FIXME: append_array, append_dict_array, append_boolean_array, append_int32_array, append_uint32_array, append_double_array + + def append_byte_array(self, list): + cdef unsigned char * value + cdef int length + length = len(list) + value = malloc(length) + for i from 0 <= i < length: + item = list[i] + if type(item) != str or len(item) != 1: + raise TypeError + value[i] = ord(item) + return dbus_message_iter_append_byte_array(self.iter, value, length) + + def append_string_array(self, list): + cdef char **value + cdef int length + length = len(list) + value = malloc(length) + for i from 0 <= i < length: + item = list[i] + if type(item) != str: + raise TypeError + value[i] = item + return dbus_message_iter_append_string_array(self.iter, value, length) + + +(MESSAGE_TYPE_INVALID, MESSAGE_TYPE_METHOD_CALL, MESSAGE_TYPE_METHOD_RETURN, MESSAGE_TYPE_ERROR, MESSAGE_TYPE_SIGNAL) = range(5) +(TYPE_INVALID, TYPE_NIL, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_NAMED, TYPE_ARRAY, TYPE_DICT, TYPE_OBJECT_PATH) = range(14) + +cdef class Message: + cdef DBusMessage *msg + + def __init__(self, message_type=MESSAGE_TYPE_INVALID, service=None, path=None, interface=None, + method=None, name=None, reply_to=None, error_name=None, error_message=None, + _create=1): + cdef char *cservice + if (service == None): + cservice = NULL + else: + cservice = service + + if not _create: + return 0 + + if message_type == MESSAGE_TYPE_METHOD_CALL: + self.msg = dbus_message_new_method_call(cservice, path, interface, method) + elif message_type == MESSAGE_TYPE_METHOD_RETURN: + msg = method_call._get_msg() + self.msg = dbus_message_new_method_return(msg) + elif message_type == MESSAGE_TYPE_SIGNAL: + self.msg = dbus_message_new_signal(path, interface, name) + elif message_type == MESSAGE_TYPE_ERROR: + msg = reply_to._get_msg() + self.msg = dbus_message_new_error(msg, error_name, error_message) + + def type_to_name(self, type): + if type == MESSAGE_TYPE_SIGNAL: + return "signal" + elif type == MESSAGE_TYPE_METHOD_CALL: + return "method call" + elif type == MESSAGE_TYPE_METHOD_RETURN: + return "method return" + elif type == MESSAGE_TYPE_ERROR: + return "error" + else: + return "(unknown message type)" + + def __str__(self): + message_type = self.get_type() + sender = self.get_sender() + + if sender == None: + sender = "(no sender)" + + if (message_type == MESSAGE_TYPE_METHOD_CALL) or (message_type == MESSAGE_TYPE_SIGNAL): + retval = '%s interface=%s; member=%s; sender=%s' % (self.type_to_name(message_type), + self.get_interface(), + self.get_member(), + sender) + elif message_type == MESSAGE_TYPE_METHOD_RETURN: + retval = '%s sender=%s' % (self.type_to_name(message_type), + sender) + elif message_type == MESSAGE_TYPE_ERROR: + retval = '%s name=%s; sender=%s' % (self.type_to_name(message_type), + self.get_error_name(), + sender) + else: + retval = "Message of unknown type %d" % (message_type) + + + # FIXME: should really use self.convert_to_tuple() here + + iter = self.get_iter() + value_at_iter = True + + while (value_at_iter): + type = iter.get_arg_type() + + if type == TYPE_INVALID: + break + elif type == TYPE_STRING: + str = iter.get_string() + arg = 'string:%s\n' % (str) + elif type == TYPE_INT32: + num = iter.get_int32() + arg = 'int32:%d\n' % (num) + elif type == TYPE_UINT32: + num = iter.get_uint32() + arg = 'uint32:%u\n' % (num) + elif type == TYPE_DOUBLE: + num = iter.get_double() + arg = 'double:%f\n' % (num) + elif type == TYPE_BYTE: + num = iter.get_byte() + arg = 'byte:%d\n' % (num) + elif type == TYPE_BOOLEAN: + bool = iter.get_boolean() + if (bool): + str = "true" + else: + str = "false" + arg = 'boolean:%s\n' % (str) + else: + arg = '(unknown arg type %d)\n' % type + + retval = retval + arg + value_at_iter = iter.next() + + return retval + + def _set_msg(self, msg): + self.msg = msg + + def _get_msg(self): + return self.msg + + def get_iter(self): + return MessageIter(self) + + def get_args_list(self): + retval = [ ] + + iter = self.get_iter() + try: + retval.append(iter.get()) + except TypeError, e: + return [ ] + + value_at_iter = iter.next() + while (value_at_iter): + retval.append(iter.get()) + value_at_iter = iter.next() + + return retval + + # FIXME: implement dbus_message_copy? + + def get_type(self): + return dbus_message_get_type(self.msg) + + def set_path(self, object_path): + return dbus_message_set_path(self.msg, object_path) + + def get_path(self): + return dbus_message_get_path(self.msg) + + def set_interface(self, interface): + return dbus_message_set_interface(self.msg, interface) + + def get_interface(self): + return dbus_message_get_interface(self.msg) + + def set_member(self, member): + return dbus_message_set_member(self.msg, member) + + def get_member(self): + return dbus_message_get_member(self.msg) + + def set_error_name(self, name): + return dbus_message_set_error_name(self.msg, name) + + def get_error_name(self): + return dbus_message_get_error_name(self.msg) + + def set_destination(self, destination): + return dbus_message_set_destination(self.msg, destination) + + def get_destination(self): + return dbus_message_get_destination(self.msg) + + def set_sender(self, sender): + return dbus_message_set_sender(self.msg, sender) + + def get_sender(self): + cdef char *sender + sender = dbus_message_get_sender(self.msg) + if (sender == NULL): + return None + else: + return sender + + def set_no_reply(self, no_reply): + dbus_message_set_no_reply(self.msg, no_reply) + + def get_no_reply(self): + return dbus_message_get_no_reply(self.msg) + + def is_method_call(self, interface, method): + return dbus_message_is_method_call(self.msg, interface, method) + + def is_signal(self, interface, signal_name): + return dbus_message_is_signal(self.msg, interface, signal_name) + + def is_error(self, error_name): + return dbus_message_is_error(self.msg, error_name) + + def has_destination(self, service): + return dbus_message_has_destination(self.msg, service) + + def has_sender(self, service): + return dbus_message_has_sender(self.msg, service) + + def get_serial(self): + return dbus_message_get_serial(self.msg) + + def set_reply_serial(self, reply_serial): + return dbus_message_set_reply_serial(self.msg, reply_serial) + + def get_reply_serial(self): + return dbus_message_get_reply_serial(self.msg) + + #FIXME: dbus_message_get_path_decomposed + + # FIXME: all the different dbus_message_*args* methods + +class Signal(Message): + def __init__(self, spath, sinterface, sname): + Message.__init__(self, MESSAGE_TYPE_SIGNAL, path=spath, interface=sinterface, name=sname) + +class MethodCall(Message): + def __init__(self, mpath, minterface, mmethod): + Message.__init__(self, MESSAGE_TYPE_METHOD_CALL, path=mpath, interface=minterface, method=mmethod) + +cdef class Server: + cdef DBusServer *server + def __init__(self, address): + cdef DBusError error + dbus_error_init(&error) + self.server = dbus_server_listen(address, + &error) + if dbus_error_is_set(&error): + raise DBusException, error.message + + def setup_with_g_main (self): + dbus_server_setup_with_g_main(self.server, NULL) + + def disconnect(self): + dbus_server_disconnect(self.server) + + def get_is_connected(self): + return dbus_server_get_is_connected(self.server) + +# def set_new_connection_function(self, function, data): +# dbus_server_set_new_connection_function(self.conn, function, +# data, NULL) + +# def set_watch_functions(self, add_function, remove_function, data): +# dbus_server_set_watch_functions(self.server, +# add_function, remove_function, +# data, NULL) + +# def set_timeout_functions(self, add_function, remove_function, data): +# dbus_server_set_timeout_functions(self.server, +# add_function, remove_function, +# data, NULL) + +# def handle_watch(self, watch, condition): +# dbus_server_handle_watch(self.conn, watch, condition) + +BUS_SESSION = DBUS_BUS_SESSION +BUS_SYSTEM = DBUS_BUS_SYSTEM +BUS_ACTIVATION = DBUS_BUS_ACTIVATION + +def bus_get (bus_type): + cdef DBusError error + dbus_error_init(&error) + cdef DBusConnection *connection + + connection = dbus_bus_get(bus_type, + &error) + + if dbus_error_is_set(&error): + raise DBusException, error.message + + return Connection(_conn=connection) + +def bus_get_base_service(connection): + conn = connection._get_conn() + return dbus_bus_get_base_service(conn) + +def bus_register(connection): + cdef DBusError error + dbus_error_init(&error) + cdef dbus_bool_t retval + + conn = connection._get_conn() + retval = dbus_bus_register(conn, + &error) + if dbus_error_is_set(&error): + raise DBusException, error.message + + return retval + +SERVICE_FLAG_PROHIBIT_REPLACEMENT = 0x1 +SERVICE_FLAG_REPLACE_EXISTING = 0x2 + +def bus_acquire_service(connection, service_name, flags=0): + cdef DBusError error + dbus_error_init(&error) + cdef int retval + + conn = connection._get_conn() + retval = dbus_bus_acquire_service(conn, + service_name, + flags, + &error) + if dbus_error_is_set(&error): + raise DBusException, error.message + return retval + +def bus_service_exists(connection, service_name): + cdef DBusError error + dbus_error_init(&error) + cdef dbus_bool_t retval + + conn = connection._get_conn() + retval = dbus_bus_service_exists(conn, + service_name, + &error) + if dbus_error_is_set(&error): + raise DBusException, error.message + return retval + + diff --git a/python/dbus_h_wrapper.h b/python/dbus_h_wrapper.h new file mode 100644 index 00000000..2e218c8c --- /dev/null +++ b/python/dbus_h_wrapper.h @@ -0,0 +1,3 @@ +#define DBUS_API_SUBJECT_TO_CHANGE 1 +#include + diff --git a/python/extract.py b/python/extract.py new file mode 100644 index 00000000..460af5ab --- /dev/null +++ b/python/extract.py @@ -0,0 +1,237 @@ +import commands +import glob +import re +import os +import string +import sys + +def clean_func(buf): + buf = strip_comments(buf) + pat = re.compile(r"""\\\n""", re.MULTILINE) + buf = pat.sub('',buf) + pat = re.compile(r"""^[#].*?$""", re.MULTILINE) + buf = pat.sub('',buf) + pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE) + buf = pat.sub('',buf) + pat = re.compile(r"""\s+""", re.MULTILINE) + buf = pat.sub(' ',buf) + pat = re.compile(r""";\s*""", re.MULTILINE) + buf = pat.sub('\n',buf) + buf = buf.lstrip() + #pat=re.compile(r'\s+([*|&]+)\s*(\w+)') + pat = re.compile(r' \s+ ([*|&]+) \s* (\w+)',re.VERBOSE) + buf = pat.sub(r'\1 \2', buf) + pat = re.compile(r'\s+ (\w+) \[ \s* \]',re.VERBOSE) + buf = pat.sub(r'[] \1', buf) +# buf = string.replace(buf, 'G_CONST_RETURN ', 'const-') + buf = string.replace(buf, 'const ', '') + return buf + +def strip_comments(buf): + parts = [] + lastpos = 0 + while 1: + pos = string.find(buf, '/*', lastpos) + if pos >= 0: + parts.append(buf[lastpos:pos]) + pos = string.find(buf, '*/', pos) + if pos >= 0: + lastpos = pos + 2 + else: + break + else: + parts.append(buf[lastpos:]) + break + return string.join(parts, '') + +def find_enums(buf): + enums = [] + buf = strip_comments(buf) + buf = re.sub('\n', ' ', buf) + + enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)') + splitter = re.compile(r'\s*,\s', re.MULTILINE) + pos = 0 + while pos < len(buf): + m = enum_pat.search(buf, pos) + if not m: break + + name = m.group(2) + vals = m.group(1) + isflags = string.find(vals, '<<') >= 0 + entries = [] + for val in splitter.split(vals): + if not string.strip(val): continue + entries.append(string.split(val)[0]) + enums.append((name, isflags, entries)) + + pos = m.end() + return enums + +#typedef unsigned int dbus_bool_t; +#typedef struct { +# +# } +#typedef struct FooStruct FooStruct; +# typedef void (* DBusAddWatchFunction) (DBusWatch *watch, +# void *data); + +def find_typedefs(buf): + typedefs = [] + buf = re.sub('\n', ' ', strip_comments(buf)) + typedef_pat = re.compile( + r"""typedef\s*(?P\w*) + \s* + ([(]\s*\*\s*(?P[\w* ]*)[)]|{([^}]*)}|) + \s* + (?P[(](?P[\s\w*,_]*)[)]|[\w ]*)""", + re.MULTILINE | re.VERBOSE) + pat = re.compile(r"""\s+""", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = typedef_pat.search(buf, pos) + if not m: + break + if m.group('type') == 'enum': + pos = m.end() + continue + if m.group('args2') != None: + args = pat.sub(' ', m.group('args2')) + + current = '%s (* %s) (%s)' % (m.group('type'), + m.group('callback'), + args) + else: + current = '%s %s' % (m.group('type'), m.group('args1')) + typedefs.append(current) + pos = m.end() + return typedefs + +proto_pat = re.compile(r""" +(?P(-|\w|\&|\*)+\s*) # return type +\s+ # skip whitespace +(?P\w+)\s*[(] # match the function name until the opening ( +(?P.*?)[)] # group the function arguments +""", re.IGNORECASE|re.VERBOSE) +arg_split_pat = re.compile("\s*,\s*") + + +def find_functions(buf): + functions = [] + buf = clean_func(buf) + buf = string.split(buf,'\n') + for p in buf: + if len(p) == 0: + continue + + m = proto_pat.match(p) + if m == None: + continue + + func = m.group('func') + ret = m.group('ret') + args = m.group('args') + args = arg_split_pat.split(args) +# for i in range(len(args)): +# spaces = string.count(args[i], ' ') +# if spaces > 1: +# args[i] = string.replace(args[i], ' ', '-', spaces - 1) + + functions.append((func, ret, args)) + return functions + +class Writer: + def __init__(self, filename, enums, typedefs, functions): + if not (enums or typedefs or functions): + return + print 'cdef extern from "%s":' % filename + + self.output_enums(enums) + self.output_typedefs(typedefs) + self.output_functions(functions) + + print ' pass' + print + + def output_enums(self, enums): + for enum in enums: + print ' ctypedef enum %s:' % enum[0] + if enum[1] == 0: + for item in enum[2]: + print ' %s' % item + else: + i = 0 + for item in enum[2]: + print ' %s' % item +# print ' %s = 1 << %d' % (item, i) + i += 1 + print + def output_typedefs(self, typedefs): + for typedef in typedefs: + if typedef.find('va_list') != -1: + continue + + parts = typedef.split() + if parts[0] == 'struct': + if parts[-2] == parts[-1]: + parts = parts[:-1] + print ' ctypedef %s' % ' '.join(parts) + else: + print ' ctypedef %s' % typedef + + def output_functions(self, functions): + for func, ret, args in functions: + if func[0] == '_': + continue + + str = ', '.join(args) + if str.find('...') != -1: + continue + if str.find('va_list') != -1: + continue + if str.strip() == 'void': + continue + print ' %-20s %s (%s)' % (ret, func, str) + +def do_buffer(name, buffer): + functions = find_functions(buffer) + typedefs = find_typedefs(buffer) + enums = find_enums(buffer) + + Writer(name, enums, typedefs, functions) + +def do_header(filename, name=None): + if name == None: + name = filename + + buffer = "" + for line in open(filename).readlines(): + if line[0] == '#': + continue + buffer += line + + print '# -- %s -- ' % filename + do_buffer(name, buffer) + +filename = sys.argv[1] + +if filename.endswith('.h'): + do_header(filename) + raise SystemExit + +cppflags = "" + +for flag in sys.argv[2:]: + cppflags = cppflags + " " + flag + +fd = open(filename) + +for line in fd.readlines(): + if line.startswith('#include'): + filename = line.split(' ')[1][1:-2] + command = "echo '%s'|cpp %s" % (line, cppflags) + sys.stderr.write('running %s' % (command)) + output = commands.getoutput(command) + do_buffer(filename, output) + else: + print line[:-1] diff --git a/test/test-service.c b/test/test-service.c index f22b1753..d07575e2 100644 --- a/test/test-service.c +++ b/test/test-service.c @@ -106,7 +106,7 @@ main (int argc, int result; dbus_error_init (&error); - connection = dbus_bus_get (DBUS_BUS_ACTIVATION, &error); + connection = dbus_bus_get (DBUS_BUS_SESSION, &error); if (connection == NULL) { _dbus_verbose ("*** Failed to open connection to activating message bus: %s\n", @@ -126,10 +126,13 @@ main (int argc, filter_func, NULL, NULL)) die ("No memory"); + printf ("Acquiring service\n"); + result = dbus_bus_acquire_service (connection, "org.freedesktop.DBus.TestSuiteEchoService", 0, &error); if (dbus_error_is_set (&error)) { + printf ("Error %s", error.message); _dbus_verbose ("*** Failed to acquire service: %s\n", error.message); dbus_error_free (&error); -- cgit v1.2.1 From 4be7b14fce835a30b312bfed1492234bf1e0f316 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 22 Sep 2003 23:50:52 +0000 Subject: 2003-09-22 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_get): implement --- ChangeLog | 4 ++++ glib/dbus-gproxy.c | 69 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 530c47c8..a094e98a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-09-22 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_gproxy_manager_get): implement + 2003-09-21 Seth Nickell First checkin of the Python bindings. diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 96a27888..57cdab2f 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -37,28 +37,61 @@ typedef struct { GStaticMutex lock; /**< Thread lock */ int refcount; /**< Reference count */ - + DBusConnection *connection; /**< Connection we're associated with. */ } DBusGProxyManager; - /** Lock the DBusGProxyManager */ #define LOCK_MANAGER(mgr) (g_static_mutex_lock (&(mgr)->lock)) /** Unlock the DBusGProxyManager */ #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock)) +static int gproxy_manager_slot = -1; + +/* Lock controlling get/set manager as data on each connection */ +static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT; + +static void dbus_gproxy_manager_ref (DBusGProxyManager *manager); + static DBusGProxyManager* -dbus_gproxy_manager_new (void) +dbus_gproxy_manager_get (DBusConnection *connection) { DBusGProxyManager *manager; + dbus_connection_allocate_data_slot (&gproxy_manager_slot); + if (gproxy_manager_slot < 0) + g_error ("out of memory"); + + g_static_mutex_lock (&connection_gproxy_lock); + + manager = dbus_connection_get_data (connection, gproxy_manager_slot); + if (manager != NULL) + { + dbus_connection_free_data_slot (&gproxy_manager_slot); + dbus_gproxy_manager_ref (manager); + g_static_mutex_unlock (&connection_gproxy_lock); + return manager; + } + manager = g_new0 (DBusGProxyManager, 1); manager->refcount = 1; + manager->connection = connection; g_static_mutex_init (&manager->lock); + /* Proxy managers keep the connection alive, which means that + * DBusGProxy indirectly does. To free a connection you have to free + * all the proxies referring to it. + */ + dbus_connection_ref (manager->connection); + + dbus_connection_set_data (connection, gproxy_manager_slot, + manager, NULL); + + g_static_mutex_unlock (&connection_gproxy_lock); + return manager; } @@ -89,7 +122,18 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager) g_static_mutex_free (&manager->lock); + g_static_mutex_lock (&connection_gproxy_lock); + + dbus_connection_set_data (manager->connection, + gproxy_manager_slot, + NULL, NULL); + + g_static_mutex_unlock (&connection_gproxy_lock); + + dbus_connection_unref (manager->connection); g_free (manager); + + dbus_connection_free_data_slot (&gproxy_manager_slot); } else { @@ -97,14 +141,6 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager) } } -static DBusGProxyManager* -dbus_gproxy_manager_get_for_connection (DBusConnection *connection) -{ - /* FIXME */ - - return NULL; -} - /** * Internals of DBusGProxy */ @@ -112,7 +148,7 @@ struct DBusGProxy { GStaticMutex lock; /**< Thread lock */ int refcount; /**< Reference count */ - DBusConnection *connection; /**< Connection to communicate over */ + DBusGProxyManager *manager; /**< Proxy manager */ char *service; /**< Service messages go to or NULL */ char *path; /**< Path messages go to or NULL */ char *interface; /**< Interface messages go to or NULL */ @@ -131,8 +167,7 @@ _dbus_gproxy_new (DBusConnection *connection) proxy = g_new0 (DBusGProxy, 1); proxy->refcount = 1; - proxy->connection = connection; - dbus_connection_ref (connection); + proxy->manager = dbus_gproxy_manager_get (connection); g_static_mutex_init (&proxy->lock); @@ -224,7 +259,7 @@ dbus_gproxy_unref (DBusGProxy *proxy) { UNLOCK_PROXY (proxy); - dbus_connection_unref (proxy->connection); + dbus_gproxy_manager_unref (proxy->manager); g_free (proxy->service); g_free (proxy->path); g_free (proxy->interface); @@ -282,7 +317,7 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, goto oom; va_end (args); - if (!dbus_connection_send_with_reply (proxy->connection, + if (!dbus_connection_send_with_reply (proxy->manager->connection, message, &pending, -1)) @@ -409,7 +444,7 @@ dbus_gproxy_send (DBusGProxy *proxy, g_error ("Out of memory"); } - if (!dbus_connection_send (proxy->connection, message, client_serial)) + if (!dbus_connection_send (proxy->manager->connection, message, client_serial)) g_error ("Out of memory\n"); UNLOCK_PROXY (proxy); -- cgit v1.2.1 From 0a34a4400619034e2be47f4387edf0204185d38b Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 23 Sep 2003 04:20:06 +0000 Subject: 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (struct DBusGProxy): convert to a GObject subclass. This means dropping the transparent thread safety of the proxy; you now need a separate proxy per-thread, or your own locking on the proxy. Probably right anyway. (dbus_gproxy_ref, dbus_gproxy_unref): nuke, just use g_object_ref --- ChangeLog | 8 +++ glib/dbus-glib.h | 20 ++++++- glib/dbus-gproxy.c | 160 ++++++++++++++++++++++++++--------------------------- 3 files changed, 106 insertions(+), 82 deletions(-) diff --git a/ChangeLog b/ChangeLog index a094e98a..ada29551 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2003-09-23 Havoc Pennington + + * glib/dbus-gproxy.c (struct DBusGProxy): convert to a GObject + subclass. This means dropping the transparent thread safety of the + proxy; you now need a separate proxy per-thread, or your own + locking on the proxy. Probably right anyway. + (dbus_gproxy_ref, dbus_gproxy_unref): nuke, just use g_object_ref + 2003-09-22 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_get): implement diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 7fd88e71..556d896e 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -87,6 +87,17 @@ void dbus_connection_register_g_object (DBusConnection *connection, typedef struct DBusGProxy DBusGProxy; +typedef struct DBusGProxyClass DBusGProxyClass; + + +#define DBUS_TYPE_GPROXY (dbus_gproxy_get_type ()) +#define DBUS_GPROXY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), DBUS_TYPE_GPROXY, DBusGProxy)) +#define DBUS_GPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DBUS_TYPE_GPROXY, DBusGProxyClass)) +#define DBUS_IS_GPROXY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), DBUS_TYPE_GPROXY)) +#define DBUS_IS_GPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUS_TYPE_GPROXY)) +#define DBUS_GPROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUS_TYPE_GPROXY, DBusGProxyClass)) + +GType dbus_gproxy_get_type (void) G_GNUC_CONST; DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, const char *service_name, @@ -104,11 +115,16 @@ DBusGProxy* dbus_gproxy_new_for_peer (DBusConnection *connection void dbus_gproxy_ref (DBusGProxy *proxy); void dbus_gproxy_unref (DBusGProxy *proxy); gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *interface_name, const char *signal_name, GCallback callback, void *data, - GFreeFunc free_data_func, - GError **error); + GFreeFunc free_data_func); +gboolean dbus_gproxy_disconnect_signal (DBusGProxy *proxy, + const char *interface_name, + const char *signal_name, + GCallback callback, + void *data); DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, const char *method, int first_arg_type, diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 57cdab2f..05a073bf 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -146,32 +146,55 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager) */ struct DBusGProxy { - GStaticMutex lock; /**< Thread lock */ - int refcount; /**< Reference count */ + GObject parent; + DBusGProxyManager *manager; /**< Proxy manager */ - char *service; /**< Service messages go to or NULL */ - char *path; /**< Path messages go to or NULL */ - char *interface; /**< Interface messages go to or NULL */ + char *service; /**< Service messages go to or NULL */ + char *path; /**< Path messages go to or NULL */ + char *interface; /**< Interface messages go to or NULL */ }; -/** Lock the DBusGProxy */ -#define LOCK_PROXY(proxy) (g_static_mutex_lock (&(proxy)->lock)) -/** Unlock the DBusGProxy */ -#define UNLOCK_PROXY(proxy) (g_static_mutex_unlock (&(proxy)->lock)) +struct DBusGProxyClass +{ + GObjectClass parent_class; +}; -static DBusGProxy* -_dbus_gproxy_new (DBusConnection *connection) +static void dbus_gproxy_init (DBusGProxy *proxy); +static void dbus_gproxy_class_init (DBusGProxyClass *klass); +static void dbus_gproxy_finalize (GObject *object); + +static void *parent_class; + +static void +dbus_gproxy_init (DBusGProxy *proxy) { - DBusGProxy *proxy; + /* Nothing */ +} - proxy = g_new0 (DBusGProxy, 1); +static void +dbus_gproxy_class_init (DBusGProxyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); - proxy->refcount = 1; - proxy->manager = dbus_gproxy_manager_get (connection); + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = dbus_gproxy_finalize; +} - g_static_mutex_init (&proxy->lock); +static void +dbus_gproxy_finalize (GObject *object) +{ + DBusGProxy *proxy; + + proxy = DBUS_GPROXY (object); + + if (proxy->manager) + dbus_gproxy_manager_unref (proxy->manager); + g_free (proxy->service); + g_free (proxy->path); + g_free (proxy->interface); - return proxy; + G_OBJECT_CLASS (parent_class)->finalize (object); } /** @} End of DBusGLibInternals */ @@ -180,6 +203,39 @@ _dbus_gproxy_new (DBusConnection *connection) * @{ */ +/** + * Standard GObject get_type() function for DBusGProxy. + * + * @returns type ID for DBusGProxy class + */ +GType +dbus_gproxy_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (DBusGProxyClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) dbus_gproxy_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (DBusGProxy), + 0, /* n_preallocs */ + (GInstanceInitFunc) dbus_gproxy_init, + }; + + object_type = g_type_register_static (G_TYPE_OBJECT, + "DBusGProxy", + &object_info, 0); + } + + return object_type; +} + /** * Creates a new proxy for a remote interface. Method calls and signal * connections over this proxy will go to the service owner; the @@ -211,8 +267,14 @@ dbus_gproxy_new_for_service (DBusConnection *connection, g_return_val_if_fail (path_name != NULL, NULL); g_return_val_if_fail (interface_name != NULL, NULL); - proxy = _dbus_gproxy_new (connection); + proxy = g_object_new (DBUS_TYPE_GPROXY, NULL); + /* These should all be construct-only mandatory properties, + * for now we just don't let people use g_object_new(). + */ + + proxy->manager = dbus_gproxy_manager_get (connection); + proxy->service = g_strdup (service_name); proxy->path = g_strdup (path_name); proxy->interface = g_strdup (interface_name); @@ -220,58 +282,6 @@ dbus_gproxy_new_for_service (DBusConnection *connection, return proxy; } -/** - * Increment reference count on proxy object. - * - * @todo use GAtomic to avoid locking - * - * @param proxy the proxy - */ -void -dbus_gproxy_ref (DBusGProxy *proxy) -{ - g_return_if_fail (proxy != NULL); - - LOCK_PROXY (proxy); - - proxy->refcount += 1; - - UNLOCK_PROXY (proxy); -} - -/** - * Decrement reference count on proxy object. - * - * @todo use GAtomic to avoid locking - * - * @param proxy the proxy - */ -void -dbus_gproxy_unref (DBusGProxy *proxy) -{ - g_return_if_fail (proxy != NULL); - - LOCK_PROXY (proxy); - - proxy->refcount -= 1; - - if (proxy->refcount == 0) - { - UNLOCK_PROXY (proxy); - - dbus_gproxy_manager_unref (proxy->manager); - g_free (proxy->service); - g_free (proxy->path); - g_free (proxy->interface); - g_static_mutex_free (&proxy->lock); - g_free (proxy); - } - else - { - UNLOCK_PROXY (proxy); - } -} - /** * Invokes a method on a remote interface. This function does not * block; instead it returns an opaque #DBusPendingCall object that @@ -302,7 +312,6 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, va_list args; g_return_val_if_fail (proxy != NULL, NULL); - LOCK_PROXY (proxy); message = dbus_message_new_method_call (proxy->service, proxy->path, @@ -322,8 +331,6 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, &pending, -1)) goto oom; - - UNLOCK_PROXY (proxy); return pending; @@ -375,8 +382,6 @@ dbus_gproxy_end_call (DBusGProxy *proxy, g_return_val_if_fail (proxy != NULL, FALSE); g_return_val_if_fail (pending != NULL, FALSE); - - LOCK_PROXY (proxy); dbus_pending_call_block (pending); message = dbus_pending_call_get_reply (pending); @@ -392,8 +397,6 @@ dbus_gproxy_end_call (DBusGProxy *proxy, } va_end (args); - UNLOCK_PROXY (proxy); - return TRUE; error: @@ -426,7 +429,6 @@ dbus_gproxy_send (DBusGProxy *proxy, dbus_uint32_t *client_serial) { g_return_if_fail (proxy != NULL); - LOCK_PROXY (proxy); if (proxy->service) { @@ -446,8 +448,6 @@ dbus_gproxy_send (DBusGProxy *proxy, if (!dbus_connection_send (proxy->manager->connection, message, client_serial)) g_error ("Out of memory\n"); - - UNLOCK_PROXY (proxy); } /** @} End of DBusGLib public */ -- cgit v1.2.1 From cefe445bea082f0891142ac4b746893e4ffb7d1f Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 23 Sep 2003 05:04:51 +0000 Subject: trivial header change --- glib/dbus-glib.h | 51 ++++++++++++++++++++++++--------------------------- glib/dbus-gproxy.c | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 556d896e..a391c4a1 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -111,36 +111,33 @@ DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection DBusGProxy* dbus_gproxy_new_for_peer (DBusConnection *connection, const char *path_name, const char *interface_name); - -void dbus_gproxy_ref (DBusGProxy *proxy); -void dbus_gproxy_unref (DBusGProxy *proxy); -gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy, - const char *interface_name, - const char *signal_name, - GCallback callback, - void *data, - GFreeFunc free_data_func); -gboolean dbus_gproxy_disconnect_signal (DBusGProxy *proxy, - const char *interface_name, - const char *signal_name, - GCallback callback, - void *data); -DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, +void dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *interface_name, + const char *signal_name, + GCallback callback, + void *data, + GFreeFunc free_data_func); +void dbus_gproxy_disconnect_signal (DBusGProxy *proxy, + const char *interface_name, + const char *signal_name, + GCallback callback, + void *data); +DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, ...); -gboolean dbus_gproxy_end_call (DBusGProxy *proxy, - DBusPendingCall *pending, - GError **error, - int first_arg_type, +gboolean dbus_gproxy_end_call (DBusGProxy *proxy, + DBusPendingCall *pending, + GError **error, + int first_arg_type, ...); -void dbus_gproxy_oneway_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, +void dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, ...); -void dbus_gproxy_send (DBusGProxy *proxy, - DBusMessage *message, - dbus_uint32_t *client_serial); +void dbus_gproxy_send (DBusGProxy *proxy, + DBusMessage *message, + dbus_uint32_t *client_serial); #undef DBUS_INSIDE_DBUS_GLIB_H diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 05a073bf..f27eb6d0 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -450,6 +450,29 @@ dbus_gproxy_send (DBusGProxy *proxy, g_error ("Out of memory\n"); } +void +dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *interface_name, + const char *signal_name, + GCallback callback, + void *data, + GFreeFunc free_data_func) +{ + + +} + +void +dbus_gproxy_disconnect_signal (DBusGProxy *proxy, + const char *interface_name, + const char *signal_name, + GCallback callback, + void *data) +{ + + +} + /** @} End of DBusGLib public */ #ifdef DBUS_BUILD_TESTS -- cgit v1.2.1 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 --- ChangeLog | 8 + bus/signals.c | 6 +- dbus/dbus-message.c | 2 +- glib/dbus-glib.h | 81 +++---- glib/dbus-gmain.c | 37 ++++ glib/dbus-gproxy.c | 629 ++++++++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 676 insertions(+), 87 deletions(-) diff --git a/ChangeLog b/ChangeLog index ada29551..a9fdc347 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +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 + 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (struct DBusGProxy): convert to a GObject diff --git a/bus/signals.c b/bus/signals.c index db7b0665..30d977c3 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -690,7 +690,11 @@ bus_matchmaker_get_recipients (BusMatchmaker *matchmaker, DBusList **recipients_p) { /* FIXME for now this is a wholly unoptimized linear search */ - + /* Guessing the important optimization is to skip the signal-related + * match lists when processing method call and exception messages. + * So separate match rule lists for signals? + */ + DBusList *link; _dbus_assert (*recipients_p == NULL); 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"); diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index a391c4a1..79c1e116 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -34,6 +34,11 @@ G_BEGIN_DECLS GQuark dbus_g_error_quark (void); #define DBUS_GERROR dbus_g_error_quark () +#define DBUS_TYPE_CONNECTION (dbus_connection_get_g_type ()) +#define DBUS_TYPE_MESSAGE (dbus_message_get_g_type ()) +GType dbus_connection_get_g_type (void) G_GNUC_CONST; +GType dbus_message_get_g_type (void) G_GNUC_CONST; + typedef enum { /* FIXME map all the DBUS_ERROR to DBUS_GERROR, should @@ -89,6 +94,9 @@ void dbus_connection_register_g_object (DBusConnection *connection, typedef struct DBusGProxy DBusGProxy; typedef struct DBusGProxyClass DBusGProxyClass; +typedef void (* DBusGProxySignalHandler) (DBusGProxy *proxy, + DBusMessage *signal, + void *user_data); #define DBUS_TYPE_GPROXY (dbus_gproxy_get_type ()) #define DBUS_GPROXY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), DBUS_TYPE_GPROXY, DBusGProxy)) @@ -97,47 +105,46 @@ typedef struct DBusGProxyClass DBusGProxyClass; #define DBUS_IS_GPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUS_TYPE_GPROXY)) #define DBUS_GPROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUS_TYPE_GPROXY, DBusGProxyClass)) -GType dbus_gproxy_get_type (void) G_GNUC_CONST; -DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, - const char *service_name, - const char *path_name, - const char *interface_name); -DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, - const char *service_name, - const char *path_name, - const char *interface_name, - GError **error); -DBusGProxy* dbus_gproxy_new_for_peer (DBusConnection *connection, - const char *path_name, - const char *interface_name); -void dbus_gproxy_connect_signal (DBusGProxy *proxy, - const char *interface_name, - const char *signal_name, - GCallback callback, - void *data, - GFreeFunc free_data_func); -void dbus_gproxy_disconnect_signal (DBusGProxy *proxy, - const char *interface_name, - const char *signal_name, - GCallback callback, - void *data); -DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, +GType dbus_gproxy_get_type (void) G_GNUC_CONST; +DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection, + const char *service_name, + const char *path_name, + const char *interface_name); +DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection, + const char *service_name, + const char *path_name, + const char *interface_name, + GError **error); +DBusGProxy* dbus_gproxy_new_for_peer (DBusConnection *connection, + const char *path_name, + const char *interface_name); +void dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *signal_name, + DBusGProxySignalHandler handler, + void *data, + GFreeFunc free_data_func); +void dbus_gproxy_disconnect_signal (DBusGProxy *proxy, + const char *signal_name, + DBusGProxySignalHandler handler, + void *data); +DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, ...); -gboolean dbus_gproxy_end_call (DBusGProxy *proxy, - DBusPendingCall *pending, - GError **error, - int first_arg_type, +gboolean dbus_gproxy_end_call (DBusGProxy *proxy, + DBusPendingCall *pending, + GError **error, + int first_arg_type, ...); -void dbus_gproxy_oneway_call (DBusGProxy *proxy, - const char *method, - int first_arg_type, +void dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, ...); -void dbus_gproxy_send (DBusGProxy *proxy, - DBusMessage *message, - dbus_uint32_t *client_serial); +void dbus_gproxy_send (DBusGProxy *proxy, + DBusMessage *message, + dbus_uint32_t *client_serial); + #undef DBUS_INSIDE_DBUS_GLIB_H diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index 2e5604dc..54a2d462 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -535,6 +535,43 @@ dbus_set_g_error (GError **gerror, derror->name, derror->message); } +/** + * Get the GLib type ID for a DBusConnection boxed type. + * + * @returns GLib type + */ +GType +dbus_connection_get_g_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("DBusConnection", + (GBoxedCopyFunc) dbus_connection_ref, + (GBoxedFreeFunc) dbus_connection_unref); + + return our_type; +} + +/** + * Get the GLib type ID for a DBusMessage boxed type. + * + * @returns GLib type + */ +GType +dbus_message_get_g_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static ("DBusMessage", + (GBoxedCopyFunc) dbus_message_ref, + (GBoxedFreeFunc) dbus_message_unref); + + return our_type; +} + + /** @} */ /* end of public API */ #ifdef DBUS_BUILD_TESTS diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index f27eb6d0..ebcbb5d4 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -21,6 +21,7 @@ * */ #include "dbus-glib.h" +#include /** * @addtogroup DBusGLibInternals @@ -28,19 +29,69 @@ * @{ */ +typedef struct DBusGProxyManager DBusGProxyManager; + +/** + * Internals of DBusGProxy + */ +struct DBusGProxy +{ + GObject parent; /**< Parent instance */ + + DBusGProxyManager *manager; /**< Proxy manager */ + char *service; /**< Service messages go to or NULL */ + char *path; /**< Path messages go to or NULL */ + char *interface; /**< Interface messages go to or NULL */ +}; + +struct DBusGProxyClass +{ + GObjectClass parent_class; +}; + +static void dbus_gproxy_init (DBusGProxy *proxy); +static void dbus_gproxy_class_init (DBusGProxyClass *klass); +static void dbus_gproxy_finalize (GObject *object); +static void dbus_gproxy_emit_received (DBusGProxy *proxy, + DBusMessage *message); + + +/** + * A list of proxies with a given service+path+interface, used to route incoming + * signals. + */ +typedef struct +{ + GSList *proxies; + + char name[4]; /**< service (empty string for none), nul byte, + * path, nul byte, + * interface, nul byte + */ + +} DBusGProxyList; + /** * DBusGProxyManager's primary task is to route signals to the proxies * those signals are emitted on. In order to do this it also has to * track the owners of the services proxies are bound to. */ -typedef struct +struct DBusGProxyManager { GStaticMutex lock; /**< Thread lock */ int refcount; /**< Reference count */ DBusConnection *connection; /**< Connection we're associated with. */ - -} DBusGProxyManager; + GHashTable *proxy_lists; /**< Hash used to route incoming signals + * and iterate over proxies + */ + +}; + +static void dbus_gproxy_manager_ref (DBusGProxyManager *manager); +static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data); /** Lock the DBusGProxyManager */ #define LOCK_MANAGER(mgr) (g_static_mutex_lock (&(mgr)->lock)) @@ -52,8 +103,6 @@ static int gproxy_manager_slot = -1; /* Lock controlling get/set manager as data on each connection */ static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT; -static void dbus_gproxy_manager_ref (DBusGProxyManager *manager); - static DBusGProxyManager* dbus_gproxy_manager_get (DBusConnection *connection) { @@ -90,6 +139,9 @@ dbus_gproxy_manager_get (DBusConnection *connection) dbus_connection_set_data (connection, gproxy_manager_slot, manager, NULL); + dbus_connection_add_filter (connection, dbus_gproxy_manager_filter, + manager, NULL); + g_static_mutex_unlock (&connection_gproxy_lock); return manager; @@ -119,10 +171,19 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager) if (manager->refcount == 0) { UNLOCK_MANAGER (manager); + + if (manager->proxy_lists) + { + g_hash_table_destroy (manager->proxy_lists); + manager->proxy_lists = NULL; + } g_static_mutex_free (&manager->lock); g_static_mutex_lock (&connection_gproxy_lock); + + dbus_connection_remove_filter (manager->connection, dbus_gproxy_manager_filter, + manager); dbus_connection_set_data (manager->connection, gproxy_manager_slot, @@ -141,29 +202,340 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager) } } -/** - * Internals of DBusGProxy - */ -struct DBusGProxy +static guint +tristring_hash (gconstpointer key) { - GObject parent; + const char *p = key; + guint h = *p; + + if (h) + { + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + } + + /* skip nul and do the next substring */ + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + /* skip nul again and another substring */ + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; - DBusGProxyManager *manager; /**< Proxy manager */ - char *service; /**< Service messages go to or NULL */ - char *path; /**< Path messages go to or NULL */ - char *interface; /**< Interface messages go to or NULL */ -}; + return h; +} -struct DBusGProxyClass +static gboolean +strequal_len (const char *a, + const char *b, + size_t *lenp) { - GObjectClass parent_class; -}; + size_t a_len; + size_t b_len; + + a_len = strlen (a); + b_len = strlen (b); + + if (a_len != b_len) + return FALSE; + + if (memcmp (a, b, a_len) != 0) + return FALSE; + + *lenp = a_len; + + return TRUE; +} + +static gboolean +tristring_equal (gconstpointer a, + gconstpointer b) +{ + const char *ap = a; + const char *bp = b; + size_t len; + + if (!strequal_len (ap, bp, &len)) + return FALSE; + + ap += len + 1; + bp += len + 1; + + if (!strequal_len (ap, bp, &len)) + return FALSE; + + ap += len + 1; + bp += len + 1; + + if (strcmp (ap, bp) != 0) + return FALSE; + + return TRUE; +} + +static char* +tristring_alloc_from_strings (size_t padding_before, + const char *service, + const char *path, + const char *interface) +{ + size_t service_len, iface_len, path_len, len; + char *tri; + + if (service) + service_len = strlen (service); + else + service_len = 0; + + path_len = strlen (path); + + iface_len = strlen (interface); + + tri = g_malloc (padding_before + service_len + path_len + iface_len + 3); + + len = padding_before; + + if (service) + memcpy (&tri[len], service, service_len); + + len += service_len; + tri[len] = '\0'; + len += 1; + + g_assert (len == (padding_before + service_len + 1)); + + memcpy (&tri[len], path, path_len); + len += path_len; + tri[len] = '\0'; + len += 1; + + g_assert (len == (padding_before + service_len + path_len + 2)); + + memcpy (&tri[len], interface, iface_len); + len += iface_len; + tri[len] = '\0'; + len += 1; + + g_assert (len == (padding_before + service_len + path_len + iface_len + 3)); + + return tri; +} + +static char* +tristring_from_proxy (DBusGProxy *proxy) +{ + return tristring_alloc_from_strings (0, + proxy->service, + proxy->path, + proxy->interface); +} + +static char* +tristring_from_message (DBusMessage *message) +{ + return tristring_alloc_from_strings (0, + dbus_message_get_sender (message), + dbus_message_get_path (message), + dbus_message_get_interface (message)); +} + +static DBusGProxyList* +gproxy_list_new (DBusGProxy *first_proxy) +{ + DBusGProxyList *list; + + list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name), + first_proxy->service, + first_proxy->path, + first_proxy->interface); + list->proxies = NULL; + + return list; +} + +static void +gproxy_list_free (DBusGProxyList *list) +{ + /* we don't hold a reference to the proxies in the list, + * as they ref the GProxyManager + */ + g_slist_free (list->proxies); + + g_free (list); +} + +static char* +gproxy_get_match_rule (DBusGProxy *proxy) +{ + /* FIXME Some sort of escaping is required here I think */ + + if (proxy->service) + return g_strdup_printf ("type='signal',service='%s',path='%s',interface='%s'", + proxy->service, proxy->path, proxy->interface); + else + return g_strdup_printf ("type='signal',path='%s',interface='%s'", + proxy->path, proxy->interface); +} + +static void +dbus_gproxy_manager_register (DBusGProxyManager *manager, + DBusGProxy *proxy) +{ + DBusGProxyList *list; + + LOCK_MANAGER (manager); + + if (manager->proxy_lists == NULL) + { + list = NULL; + manager->proxy_lists = g_hash_table_new_full (tristring_hash, + tristring_equal, + NULL, + (GFreeFunc) gproxy_list_free); + } + else + { + char *tri; + + tri = tristring_from_proxy (proxy); + + list = g_hash_table_lookup (manager->proxy_lists, tri); + + g_free (tri); + } + + if (list == NULL) + { + list = gproxy_list_new (proxy); + + g_hash_table_replace (manager->proxy_lists, + list->name, list); + } + + if (list->proxies == NULL) + { + /* We have to add the match rule to the server, + * but FIXME only if the server is a message bus, + * not if it's a peer. + */ + char *rule; + + rule = gproxy_get_match_rule (proxy); + + /* We don't check for errors; it's not like anyone would handle them, + * and we don't want a round trip here. + */ + dbus_bus_add_match (manager->connection, + rule, NULL); + + g_free (rule); + } + + g_assert (g_slist_find (list->proxies, proxy) == NULL); + + list->proxies = g_slist_prepend (list->proxies, proxy); + + UNLOCK_MANAGER (manager); +} + +static void +dbus_gproxy_manager_unregister (DBusGProxyManager *manager, + DBusGProxy *proxy) +{ + DBusGProxyList *list; + char *tri; + + LOCK_MANAGER (manager); + + if (manager->proxy_lists == NULL) + { + g_warning ("Trying to disconnect a signal on a proxy but none are connected\n"); + return; + } + + tri = tristring_from_proxy (proxy); + + list = g_hash_table_lookup (manager->proxy_lists, tri); + + g_free (tri); + + if (list == NULL) + { + g_warning ("Trying to disconnect a signal on a proxy but none are connected\n"); + return; + } + + g_assert (g_slist_find (list->proxies, proxy) != NULL); + + list->proxies = g_slist_remove (list->proxies, proxy); + + g_assert (g_slist_find (list->proxies, proxy) == NULL); + + UNLOCK_MANAGER (manager); +} + +static DBusHandlerResult +dbus_gproxy_manager_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + DBusGProxyManager *manager; + + manager = user_data; + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, + "Disconnected")) + { + /* FIXME g_object_run_dispose() all the proxies; should proxies have + * a "destroy" signal? + */ + } + else + { + char *tri; + DBusGProxyList *list; + + tri = tristring_from_message (message); -static void dbus_gproxy_init (DBusGProxy *proxy); -static void dbus_gproxy_class_init (DBusGProxyClass *klass); -static void dbus_gproxy_finalize (GObject *object); + if (manager->proxy_lists) + list = g_hash_table_lookup (manager->proxy_lists, tri); + else + list = NULL; + + g_free (tri); + + if (list != NULL) + { + /* FIXME Emit the signal on each proxy in the list */ + + + } + } + + /* "Handling" signals doesn't make sense, they are for everyone + * who cares + */ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + + +/* ---------- DBusGProxy -------------- */ + + + +enum +{ + RECEIVED, + LAST_SIGNAL +}; static void *parent_class; +static guint signals[LAST_SIGNAL] = { 0 }; static void dbus_gproxy_init (DBusGProxy *proxy) @@ -179,6 +551,16 @@ dbus_gproxy_class_init (DBusGProxyClass *klass) parent_class = g_type_class_peek_parent (klass); object_class->finalize = dbus_gproxy_finalize; + + signals[RECEIVED] = + g_signal_new ("received", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, + DBUS_TYPE_MESSAGE); } static void @@ -189,7 +571,11 @@ dbus_gproxy_finalize (GObject *object) proxy = DBUS_GPROXY (object); if (proxy->manager) - dbus_gproxy_manager_unref (proxy->manager); + { + dbus_gproxy_manager_unregister (proxy->manager, proxy); + dbus_gproxy_manager_unref (proxy->manager); + } + g_free (proxy->service); g_free (proxy->path); g_free (proxy->interface); @@ -197,6 +583,53 @@ dbus_gproxy_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static char* +create_signal_detail (const char *interface, + const char *signal) +{ + GString *str; + + str = g_string_new (interface); + + g_string_append (str, "."); + + g_string_append (str, signal); + + return g_string_free (str, FALSE); +} + +static void +dbus_gproxy_emit_received (DBusGProxy *proxy, + DBusMessage *message) +{ + const char *interface; + const char *signal; + char *detail; + GQuark q; + + interface = dbus_message_get_interface (message); + signal = dbus_message_get_member (message); + + g_assert (interface != NULL); + g_assert (signal != NULL); + + detail = create_signal_detail (interface, signal); + + /* If the quark isn't preexisting, there's no way there + * are any handlers connected. We don't want to create + * extra quarks for every possible signal. + */ + q = g_quark_try_string (detail); + + if (q != 0) + g_signal_emit (G_OBJECT (proxy), + signals[RECEIVED], + q, + message); + + g_free (detail); +} + /** @} End of DBusGLibInternals */ /** @addtogroup DBusGLib @@ -236,6 +669,33 @@ dbus_gproxy_get_type (void) return object_type; } +static DBusGProxy* +dbus_gproxy_new (DBusConnection *connection, + const char *service_name, + const char *path_name, + const char *interface_name) +{ + DBusGProxy *proxy; + + g_assert (connection != NULL); + + proxy = g_object_new (DBUS_TYPE_GPROXY, NULL); + + /* These should all be construct-only mandatory properties, + * for now we just don't let people use g_object_new(). + */ + + proxy->manager = dbus_gproxy_manager_get (connection); + + proxy->service = g_strdup (service_name); + proxy->path = g_strdup (path_name); + proxy->interface = g_strdup (interface_name); + + dbus_gproxy_manager_register (proxy->manager, proxy); + + return proxy; +} + /** * Creates a new proxy for a remote interface. Method calls and signal * connections over this proxy will go to the service owner; the @@ -267,17 +727,8 @@ dbus_gproxy_new_for_service (DBusConnection *connection, g_return_val_if_fail (path_name != NULL, NULL); g_return_val_if_fail (interface_name != NULL, NULL); - proxy = g_object_new (DBUS_TYPE_GPROXY, NULL); - - /* These should all be construct-only mandatory properties, - * for now we just don't let people use g_object_new(). - */ - - proxy->manager = dbus_gproxy_manager_get (connection); - - proxy->service = g_strdup (service_name); - proxy->path = g_strdup (path_name); - proxy->interface = g_strdup (interface_name); + proxy = dbus_gproxy_new (connection, service_name, + path_name, interface_name); return proxy; } @@ -311,7 +762,7 @@ dbus_gproxy_begin_call (DBusGProxy *proxy, DBusMessage *message; va_list args; - g_return_val_if_fail (proxy != NULL, NULL); + g_return_val_if_fail (DBUS_IS_GPROXY (proxy), NULL); message = dbus_message_new_method_call (proxy->service, proxy->path, @@ -380,7 +831,7 @@ dbus_gproxy_end_call (DBusGProxy *proxy, va_list args; DBusError derror; - g_return_val_if_fail (proxy != NULL, FALSE); + g_return_val_if_fail (DBUS_IS_GPROXY (proxy), FALSE); g_return_val_if_fail (pending != NULL, FALSE); dbus_pending_call_block (pending); @@ -405,6 +856,52 @@ dbus_gproxy_end_call (DBusGProxy *proxy, return FALSE; } +/** + * Sends a method call message as with dbus_gproxy_begin_call(), but + * does not ask for a reply or allow you to receive one. + * + * @todo this particular function shouldn't die on out of memory, + * since you should be able to do a call with large arguments. + * + * @param proxy a proxy for a remote interface + * @param method the name of the method to invoke + * @param first_arg_type type of the first argument + */ +void +dbus_gproxy_oneway_call (DBusGProxy *proxy, + const char *method, + int first_arg_type, + ...) +{ + DBusMessage *message; + va_list args; + + g_return_if_fail (DBUS_IS_GPROXY (proxy)); + + message = dbus_message_new_method_call (proxy->service, + proxy->path, + proxy->interface, + method); + if (message == NULL) + goto oom; + + dbus_message_set_no_reply (message, TRUE); + + va_start (args, first_arg_type); + if (!dbus_message_append_args_valist (message, first_arg_type, + args)) + goto oom; + va_end (args); + + if (!dbus_connection_send (proxy->manager->connection, + message, + NULL)) + goto oom; + + oom: + g_error ("Out of memory"); +} + /** * Sends a message to the interface we're proxying for. Does not * block or wait for a reply. The message is only actually written out @@ -428,7 +925,7 @@ dbus_gproxy_send (DBusGProxy *proxy, DBusMessage *message, dbus_uint32_t *client_serial) { - g_return_if_fail (proxy != NULL); + g_return_if_fail (DBUS_IS_GPROXY (proxy)); if (proxy->service) { @@ -451,26 +948,62 @@ dbus_gproxy_send (DBusGProxy *proxy, } void -dbus_gproxy_connect_signal (DBusGProxy *proxy, - const char *interface_name, - const char *signal_name, - GCallback callback, - void *data, - GFreeFunc free_data_func) +dbus_gproxy_connect_signal (DBusGProxy *proxy, + const char *signal_name, + DBusGProxySignalHandler handler, + void *data, + GFreeFunc free_data_func) { + GClosure *closure; + char *detail; + g_return_if_fail (DBUS_IS_GPROXY (proxy)); + g_return_if_fail (signal_name != NULL); + g_return_if_fail (handler != NULL); + + detail = create_signal_detail (proxy->interface, signal_name); + + closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func); + g_signal_connect_closure_by_id (G_OBJECT (proxy), + signals[RECEIVED], + g_quark_from_string (detail), + closure, FALSE); + g_free (detail); } void -dbus_gproxy_disconnect_signal (DBusGProxy *proxy, - const char *interface_name, - const char *signal_name, - GCallback callback, - void *data) +dbus_gproxy_disconnect_signal (DBusGProxy *proxy, + const char *signal_name, + DBusGProxySignalHandler handler, + void *data) { + char *detail; + GQuark q; - + g_return_if_fail (DBUS_IS_GPROXY (proxy)); + g_return_if_fail (signal_name != NULL); + g_return_if_fail (handler != NULL); + + detail = create_signal_detail (proxy->interface, signal_name); + q = g_quark_try_string (detail); + g_free (detail); + + if (q == 0) + { + g_warning ("%s: No signal handlers for %s found on this DBusGProxy", + G_GNUC_FUNCTION, signal_name); + return; + } + + g_signal_handlers_disconnect_matched (G_OBJECT (proxy), + G_SIGNAL_MATCH_DETAIL | + G_SIGNAL_MATCH_FUNC | + G_SIGNAL_MATCH_DATA, + signals[RECEIVED], + q, + NULL, + G_CALLBACK (handler), data); } /** @} End of DBusGLib public */ -- cgit v1.2.1 From 31881de7dafad50446d2b0c8c0c96aa87a70ba61 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 24 Sep 2003 02:58:14 +0000 Subject: 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement --- ChangeLog | 4 + glib/dbus-glib.h | 2 +- glib/dbus-gproxy.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 246 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index a9fdc347..76fa41d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-09-23 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement + 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_connect_signal): implement diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 79c1e116..46f4555d 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -123,7 +123,7 @@ void dbus_gproxy_connect_signal (DBusGProxy *pr const char *signal_name, DBusGProxySignalHandler handler, void *data, - GFreeFunc free_data_func); + GClosureNotify free_data_func); void dbus_gproxy_disconnect_signal (DBusGProxy *proxy, const char *signal_name, DBusGProxySignalHandler handler, diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index ebcbb5d4..99900e4c 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -44,6 +44,9 @@ struct DBusGProxy char *interface; /**< Interface messages go to or NULL */ }; +/** + * Class struct for DBusGProxy + */ struct DBusGProxyClass { GObjectClass parent_class; @@ -52,6 +55,8 @@ struct DBusGProxyClass static void dbus_gproxy_init (DBusGProxy *proxy); static void dbus_gproxy_class_init (DBusGProxyClass *klass); static void dbus_gproxy_finalize (GObject *object); +static void dbus_gproxy_dispose (GObject *object); +static void dbus_gproxy_destroy (DBusGProxy *proxy); static void dbus_gproxy_emit_received (DBusGProxy *proxy, DBusMessage *message); @@ -174,6 +179,11 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager) if (manager->proxy_lists) { + /* can't have any proxies left since they hold + * a reference to the proxy manager. + */ + g_assert (g_hash_table_size (manager->proxy_lists) == 0); + g_hash_table_destroy (manager->proxy_lists); manager->proxy_lists = NULL; } @@ -447,11 +457,13 @@ dbus_gproxy_manager_unregister (DBusGProxyManager *manager, LOCK_MANAGER (manager); +#ifndef G_DISABLE_CHECKS if (manager->proxy_lists == NULL) { g_warning ("Trying to disconnect a signal on a proxy but none are connected\n"); return; } +#endif tri = tristring_from_proxy (proxy); @@ -459,21 +471,70 @@ dbus_gproxy_manager_unregister (DBusGProxyManager *manager, g_free (tri); +#ifndef G_DISABLE_CHECKS if (list == NULL) { g_warning ("Trying to disconnect a signal on a proxy but none are connected\n"); return; } +#endif g_assert (g_slist_find (list->proxies, proxy) != NULL); list->proxies = g_slist_remove (list->proxies, proxy); g_assert (g_slist_find (list->proxies, proxy) == NULL); + + if (g_hash_table_size (manager->proxy_lists) == 0) + { + g_hash_table_destroy (manager->proxy_lists); + manager->proxy_lists = NULL; + } UNLOCK_MANAGER (manager); } +static void +list_proxies_foreach (gpointer key, + gpointer value, + gpointer user_data) +{ + DBusGProxyList *list; + GSList **ret; + GSList *tmp; + + list = value; + ret = user_data; + + tmp = list->proxies; + while (tmp != NULL) + { + DBusGProxy *proxy = DBUS_GPROXY (tmp->data); + + g_object_ref (proxy); + *ret = g_slist_prepend (*ret, proxy); + + tmp = tmp->next; + } +} + +static GSList* +dbus_gproxy_manager_list_all (DBusGProxyManager *manager) +{ + GSList *ret; + + ret = NULL; + + if (manager->proxy_lists) + { + g_hash_table_foreach (manager->proxy_lists, + list_proxies_foreach, + &ret); + } + + return ret; +} + static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection *connection, DBusMessage *message, @@ -481,18 +542,48 @@ dbus_gproxy_manager_filter (DBusConnection *connection, { DBusGProxyManager *manager; - manager = user_data; - if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + manager = user_data; + + dbus_gproxy_manager_ref (manager); + + LOCK_MANAGER (manager); + if (dbus_message_is_signal (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected")) { - /* FIXME g_object_run_dispose() all the proxies; should proxies have - * a "destroy" signal? + /* Destroy all the proxies, quite possibly resulting in unreferencing + * the proxy manager and the connection as well. */ + GSList *all; + GSList *tmp; + + all = dbus_gproxy_manager_list_all (manager); + + tmp = all; + while (tmp != NULL) + { + DBusGProxy *proxy; + + proxy = DBUS_GPROXY (tmp->data); + + UNLOCK_MANAGER (manager); + dbus_gproxy_destroy (proxy); + g_object_unref (G_OBJECT (proxy)); + LOCK_MANAGER (manager); + + tmp = tmp->next; + } + + g_slist_free (all); + +#ifndef G_DISABLE_CHECKS + if (manager->proxy_lists != NULL) + g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak."); +#endif } else { @@ -507,14 +598,38 @@ dbus_gproxy_manager_filter (DBusConnection *connection, list = NULL; g_free (tri); + + /* Emit the signal */ if (list != NULL) { - /* FIXME Emit the signal on each proxy in the list */ - + GSList *tmp; + GSList *copy; + copy = g_slist_copy (list->proxies); + g_slist_foreach (copy, (GFunc) g_object_ref, NULL); + + tmp = copy; + while (tmp != NULL) + { + DBusGProxy *proxy; + + proxy = DBUS_GPROXY (tmp->data); + + UNLOCK_MANAGER (manager); + dbus_gproxy_emit_received (proxy, message); + g_object_unref (G_OBJECT (proxy)); + LOCK_MANAGER (manager); + + tmp = tmp->next; + } + + g_slist_free (copy); } } + + UNLOCK_MANAGER (manager); + dbus_gproxy_manager_unref (manager); /* "Handling" signals doesn't make sense, they are for everyone * who cares @@ -530,6 +645,7 @@ dbus_gproxy_manager_filter (DBusConnection *connection, enum { + DESTROY, RECEIVED, LAST_SIGNAL }; @@ -551,7 +667,17 @@ dbus_gproxy_class_init (DBusGProxyClass *klass) parent_class = g_type_class_peek_parent (klass); object_class->finalize = dbus_gproxy_finalize; - + object_class->dispose = dbus_gproxy_dispose; + + signals[DESTROY] = + g_signal_new ("destroy", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[RECEIVED] = g_signal_new ("received", G_OBJECT_CLASS_TYPE (object_class), @@ -563,6 +689,19 @@ dbus_gproxy_class_init (DBusGProxyClass *klass) DBUS_TYPE_MESSAGE); } + +static void +dbus_gproxy_dispose (GObject *object) +{ + DBusGProxy *proxy; + + proxy = DBUS_GPROXY (object); + + g_signal_emit (object, signals[DESTROY], 0); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + static void dbus_gproxy_finalize (GObject *object) { @@ -583,6 +722,15 @@ dbus_gproxy_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +dbus_gproxy_destroy (DBusGProxy *proxy) +{ + /* FIXME do we need the GTK_IN_DESTRUCTION style flag + * from GtkObject? + */ + g_object_run_dispose (G_OBJECT (proxy)); +} + static char* create_signal_detail (const char *interface, const char *signal) @@ -697,18 +845,22 @@ dbus_gproxy_new (DBusConnection *connection, } /** - * Creates a new proxy for a remote interface. Method calls and signal - * connections over this proxy will go to the service owner; the - * service owner is expected to support the given interface name. THE - * SERVICE OWNER MAY CHANGE OVER TIME, for example between two - * different method calls. If you need a fixed owner, you need to - * request the current owner and bind a proxy to that rather than to - * the generic service name; see dbus_gproxy_new_for_service_owner(). + * Creates a new proxy for a remote interface exported by a service on + * a message bus. Method calls and signal connections over this proxy + * will go to the service owner; the service owner is expected to + * support the given interface name. THE SERVICE OWNER MAY CHANGE OVER + * TIME, for example between two different method calls. If you need a + * fixed owner, you need to request the current owner and bind a proxy + * to that rather than to the generic service name; see + * dbus_gproxy_new_for_service_owner(). * * A service-associated proxy only makes sense with a message bus, * not for app-to-app direct dbus connections. * - * @param connection the connection to the remote bus or app + * This proxy will only emit the "destroy" signal if the #DBusConnection + * is disconnected or the proxy is has no remaining references. + * + * @param connection the connection to the remote bus * @param service_name name of the service on the message bus * @param path_name name of the object inside the service to call methods on * @param interface_name name of the interface to call methods on @@ -733,6 +885,75 @@ dbus_gproxy_new_for_service (DBusConnection *connection, return proxy; } +/** + * Similar to dbus_gproxy_new_for_service(), but makes a round-trip + * request to the message bus to get the current service owner, then + * binds the proxy specifically to the current owner. As a result, the + * service owner will not change over time, and the proxy will emit + * the "destroy" signal when the owner disappears from the message + * bus. + * + * An example of the difference between dbus_gproxy_new_for_service() + * and dbus_gproxy_new_for_service_owner(): if you pass the service name + * "org.freedesktop.Database" dbus_gproxy_new_for_service() remains bound + * to that name as it changes owner. dbus_gproxy_new_for_service_owner() + * will fail if the service has no owner. If the service has an owner, + * dbus_gproxy_new_for_service_owner() will bind to the unique name + * of that owner rather than the generic service name. + * + * @param connection the connection to the remote bus + * @param service_name name of the service on the message bus + * @param path_name name of the object inside the service to call methods on + * @param interface_name name of the interface to call methods on + * @param error return location for an error + * @returns new proxy object, or #NULL on error + */ +DBusGProxy* +dbus_gproxy_new_for_service_owner (DBusConnection *connection, + const char *service_name, + const char *path_name, + const char *interface_name, + GError **error) +{ + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (path_name != NULL, NULL); + g_return_val_if_fail (interface_name != NULL, NULL); + + +} + +/** + * Creates a proxy for an object in peer application (one + * we're directly connected to). That is, this function is + * intended for use when there's no message bus involved, + * we're doing a simple 1-to-1 communication between two + * applications. + * + * + * @param connection the connection to the peer + * @param path_name name of the object inside the peer to call methods on + * @param interface_name name of the interface to call methods on + * @returns new proxy object + * + */ +DBusGProxy* +dbus_gproxy_new_for_peer (DBusConnection *connection, + const char *path_name, + const char *interface_name) +{ + DBusGProxy *proxy; + + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (path_name != NULL, NULL); + g_return_val_if_fail (interface_name != NULL, NULL); + + proxy = dbus_gproxy_new (connection, NULL, + path_name, interface_name); + + return proxy; +} + /** * Invokes a method on a remote interface. This function does not * block; instead it returns an opaque #DBusPendingCall object that @@ -952,7 +1173,7 @@ dbus_gproxy_connect_signal (DBusGProxy *proxy, const char *signal_name, DBusGProxySignalHandler handler, void *data, - GFreeFunc free_data_func) + GClosureNotify free_data_func) { GClosure *closure; char *detail; @@ -989,12 +1210,14 @@ dbus_gproxy_disconnect_signal (DBusGProxy *proxy, q = g_quark_try_string (detail); g_free (detail); +#ifndef G_DISABLE_CHECKS if (q == 0) { g_warning ("%s: No signal handlers for %s found on this DBusGProxy", G_GNUC_FUNCTION, signal_name); return; } +#endif g_signal_handlers_disconnect_matched (G_OBJECT (proxy), G_SIGNAL_MATCH_DETAIL | @@ -1018,7 +1241,8 @@ dbus_gproxy_disconnect_signal (DBusGProxy *proxy, dbus_bool_t _dbus_gproxy_test (void) { - + + return TRUE; } -- cgit v1.2.1 From 6f5fc71b10ab910612b7af767308f52bb8266b1e Mon Sep 17 00:00:00 2001 From: Seth Nickell Date: Thu, 25 Sep 2003 06:57:01 +0000 Subject: 2003-09-24 Seth Nickell * python/dbus.py: Connect Object methods (when you are sharing an object) up... pass in a list of methods to be shared. Sharing all the methods just worked out too weird. You can now create nice Services over the DBus in Python. :-) * python/dbus_bindings.pyx.in: Keep references to user_data tuples passed into C functions so Python doesn't garbage collect on us. Implement MethodReturn and Error subclasses of Message for creating DBusMessage's of those types. * python/examples/example-client.py: * python/examples/example-service.py: Simple example code showing both how create DBus services and objects, and how to use them. --- ChangeLog | 23 ++++++++++++++++++++++ python/dbus.py | 25 ++++++++++++++++++++---- python/dbus_bindings.pyx.in | 40 ++++++++++++++++++++++++++------------ python/examples/example-client.py | 9 +++++++++ python/examples/example-service.py | 16 +++++++++++++++ 5 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 python/examples/example-client.py create mode 100644 python/examples/example-service.py diff --git a/ChangeLog b/ChangeLog index 76fa41d2..17b4fd4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2003-09-24 Seth Nickell + + * python/dbus.py: + + Connect Object methods (when you are sharing an object) up... pass + in a list of methods to be shared. Sharing all the methods just + worked out too weird. You can now create nice Services over the + DBus in Python. :-) + + * python/dbus_bindings.pyx.in: + + Keep references to user_data tuples passed into C functions so + Python doesn't garbage collect on us. + + Implement MethodReturn and Error subclasses of Message for creating + DBusMessage's of those types. + + * python/examples/example-client.py: + * python/examples/example-service.py: + + Simple example code showing both how create DBus services and objects, + and how to use them. + 2003-09-23 Havoc Pennington * glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement diff --git a/python/dbus.py b/python/dbus.py index a7cca56a..55e5944a 100644 --- a/python/dbus.py +++ b/python/dbus.py @@ -159,18 +159,35 @@ class Object: def __init__(self, object_path, methods_to_share, service): self._object_path = object_path self._service = service - self._object_methods = methods_to_share self._bus = service.get_bus() self._connection = self._bus.get_connection() + + self._method_name_to_method = self._build_method_dictionary(methods_to_share) self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb) def _unregister_cb(self, connection): print ("Unregister") - def message_cb(self, connection, message): - print ("Message %s received" % (message)) - print ("MethodCall %s" % (message.get_member())) + def _message_cb(self, connection, message): + target_method_name = message.get_member() + target_method = self._method_name_to_method[target_method_name] + args = message.get_args_list() + + retval = target_method(*args) + + reply = dbus_bindings.MethodReturn(message) + if retval != None: + reply.append(retval) + self._connection.send(reply) + + def _build_method_dictionary(self, methods): + dictionary = {} + for method in methods: + if dictionionary.has_key(method.__name__): + print ('WARNING: registering DBus Object methods, already have a method named %s' % (method.__name__) + dictionary[method.__name__] = method + return dictionary class RemoteService: """A remote service providing objects. diff --git a/python/dbus_bindings.pyx.in b/python/dbus_bindings.pyx.in index 2e575edc..085a73fa 100644 --- a/python/dbus_bindings.pyx.in +++ b/python/dbus_bindings.pyx.in @@ -53,6 +53,8 @@ ctypedef struct DBusObjectPathVTable: void (* dbus_internal_pad4) (void *) +_user_data_references = [ ] + class DBusException(Exception): pass @@ -72,6 +74,7 @@ cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection, void *user_data): print ("cmessage_function_handler() called") tup = user_data + print (type(tup)) print (tup) function = tup[1] message = Message(_create=0) @@ -102,7 +105,7 @@ cdef class Connection: # FIXME: this is a major major hack. We use this because casting values to # python objects and returning seemed to be corrupting them. This is a "global variable" :-( cdef char **_parsed_path - + def __init__(self, address=None, _conn=None): cdef DBusError error dbus_error_init(&error) @@ -301,7 +304,8 @@ cdef class Connection: cvtable.message_function = cmessage_function_handler user_data = [unregister_cb, message_cb] - #Py_XINCREF(user_data) + global _user_data_references + _user_data_references.append(user_data) path_element_list = path[1:].split('/') self._build_parsed_path(path_element_list) @@ -316,9 +320,8 @@ cdef class Connection: cvtable.message_function = cmessage_function_handler user_data = [unregister_cb, message_cb] - Py_XINCREF(user_data) - - print ("Ref inced") + global _user_data_references + _user_data_references.append(user_data) path_element_list = path[1:].split('/') self._build_parsed_path(path_element_list) @@ -586,8 +589,11 @@ cdef class MessageIter: cdef class Message: cdef DBusMessage *msg - def __init__(self, message_type=MESSAGE_TYPE_INVALID, service=None, path=None, interface=None, - method=None, name=None, reply_to=None, error_name=None, error_message=None, + def __init__(self, message_type=MESSAGE_TYPE_INVALID, + service=None, path=None, interface=None, method=None, + method_call=None, + name=None, + reply_to=None, error_name=None, error_message=None, _create=1): cdef char *cservice if (service == None): @@ -596,18 +602,20 @@ cdef class Message: cservice = service if not _create: - return 0 + return if message_type == MESSAGE_TYPE_METHOD_CALL: self.msg = dbus_message_new_method_call(cservice, path, interface, method) elif message_type == MESSAGE_TYPE_METHOD_RETURN: - msg = method_call._get_msg() - self.msg = dbus_message_new_method_return(msg) + print ("Doing this") + cmsg = method_call._get_msg() + self.msg = dbus_message_new_method_return(cmsg) + print ("Done") elif message_type == MESSAGE_TYPE_SIGNAL: self.msg = dbus_message_new_signal(path, interface, name) elif message_type == MESSAGE_TYPE_ERROR: - msg = reply_to._get_msg() - self.msg = dbus_message_new_error(msg, error_name, error_message) + cmsg = reply_to._get_msg() + self.msg = dbus_message_new_error(cmsg, error_name, error_message) def type_to_name(self, type): if type == MESSAGE_TYPE_SIGNAL: @@ -797,6 +805,14 @@ class MethodCall(Message): def __init__(self, mpath, minterface, mmethod): Message.__init__(self, MESSAGE_TYPE_METHOD_CALL, path=mpath, interface=minterface, method=mmethod) +class MethodReturn(Message): + def __init__(self, method_call): + Message.__init__(self, MESSAGE_TYPE_METHOD_RETURN, method_call=method_call) + +class Error(Message): + def __init__(self, reply_to, error_name, error_message): + Message.__init__(self, MESSAGE_TYPE_ERROR, reply_to=reply_to, error_name=error_name, error_message=error_message) + cdef class Server: cdef DBusServer *server def __init__(self, address): diff --git a/python/examples/example-client.py b/python/examples/example-client.py new file mode 100644 index 00000000..24906b83 --- /dev/null +++ b/python/examples/example-client.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +import dbus + +bus = dbus.Bus() +remote_service = bus.get_service("org.designfu.SampleService") +remote_object = remote_service.get_object("/MyObject", "org.designfu.SampleInterface") + +remote_object.HelloWorld("Hello from example-client.py!") diff --git a/python/examples/example-service.py b/python/examples/example-service.py new file mode 100644 index 00000000..eb55af44 --- /dev/null +++ b/python/examples/example-service.py @@ -0,0 +1,16 @@ +import dbus + +import pygtk +import gtk + +class MyObject(dbus.Object): + def __init__(self): + service = dbus.Service("org.designfu.SampleService") + dbus.Object("/MyObject", [self.HelloWorld], service) + + def HelloWorld(self, arg1): + print ("Hello World!: %s" % (arg1)) + +object = MyObject() + +gtk.main() -- cgit v1.2.1 From dcc037cc1f008eae9f6a35aca5b1935459e44647 Mon Sep 17 00:00:00 2001 From: Seth Nickell Date: Thu, 25 Sep 2003 08:46:39 +0000 Subject: 2003-09-25 Seth Nickell * python/dbus.py: * python/dbus_bindings.pyx.in: Handle return values. * python/examples/example-client.py: * python/examples/example-service.py: Pass back return values from the service to the client. --- ChangeLog | 12 +++++++++++ python/dbus.py | 41 +++++++++++++++++++++----------------- python/dbus_bindings.pyx.in | 15 ++++---------- python/examples/example-client.py | 7 +++++-- python/examples/example-service.py | 7 ++++--- 5 files changed, 48 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 17b4fd4e..36abf234 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2003-09-25 Seth Nickell + + * python/dbus.py: + * python/dbus_bindings.pyx.in: + + Handle return values. + + * python/examples/example-client.py: + * python/examples/example-service.py: + + Pass back return values from the service to the client. + 2003-09-24 Seth Nickell * python/dbus.py: diff --git a/python/dbus.py b/python/dbus.py index 55e5944a..d09b3fec 100644 --- a/python/dbus.py +++ b/python/dbus.py @@ -105,25 +105,20 @@ class RemoteMethod: self._method_name = method_name def __call__(self, *args): - print ("Going to call object(%s).interface(%s).method(%s)" - % (self._object_path, self._interface, self._method_name)) - message = dbus_bindings.MethodCall(self._object_path, self._interface, self._method_name) message.set_destination(self._service_name) # Add the arguments to the function iter = message.get_iter() for arg in args: - print ("Adding arg %s" % (arg)) - print ("Append success is %d" % (iter.append(arg))) - print ("Args now %s" % (message.get_args_list())) + iter.append(arg) reply_message = self._connection.send_with_reply_and_block(message, 5000) args_tuple = reply_message.get_args_list() - if (len(args_tuple) == 0): + if len(args_tuple) == 0: return - elif (len(args_tuple) == 1): + elif len(args_tuple) == 1: return args_tuple[0] else: return args_tuple @@ -174,20 +169,30 @@ class Object: target_method = self._method_name_to_method[target_method_name] args = message.get_args_list() - retval = target_method(*args) - - reply = dbus_bindings.MethodReturn(message) - if retval != None: - reply.append(retval) + try: + retval = target_method(*args) + except Exception, e: + if e.__module__ == '__main__': + error_name = e.__class__ + else: + error_name = e.__module__ + '.' + str(e.__class__) + error_contents = str(e) + reply = dbus_bindings.Error(message, error_name, error_contents) + else: + reply = dbus_bindings.MethodReturn(message) + if retval != None: + iter = reply.get_iter() + iter.append(retval) + self._connection.send(reply) def _build_method_dictionary(self, methods): - dictionary = {} + method_dict = {} for method in methods: - if dictionionary.has_key(method.__name__): - print ('WARNING: registering DBus Object methods, already have a method named %s' % (method.__name__) - dictionary[method.__name__] = method - return dictionary + if method_dict.has_key(method.__name__): + print ('WARNING: registering DBus Object methods, already have a method named %s' % (method.__name__)) + method_dict[method.__name__] = method + return method_dict class RemoteService: """A remote service providing objects. diff --git a/python/dbus_bindings.pyx.in b/python/dbus_bindings.pyx.in index 085a73fa..8feb8678 100644 --- a/python/dbus_bindings.pyx.in +++ b/python/dbus_bindings.pyx.in @@ -63,8 +63,8 @@ class ConnectionError(Exception): cdef void cunregister_function_handler (DBusConnection *connection, void *user_data): - print ("cunregister_function_handler() called") tup = user_data + assert (type(tup) == list) function = tup[0] args = [Connection(_conn=connection)] function(*args) @@ -72,10 +72,8 @@ cdef void cunregister_function_handler (DBusConnection *connection, cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection, DBusMessage *msg, void *user_data): - print ("cmessage_function_handler() called") tup = user_data - print (type(tup)) - print (tup) + assert (type(tup) == list) function = tup[1] message = Message(_create=0) message._set_msg(msg) @@ -90,6 +88,7 @@ cdef DBusHandlerResult chandle_message_function_handler (DBusConnection *connect DBusMessage *msg, void *user_data): function = user_data + assert (type(function) == function) messagein = Message(_create=0) messagein._set_msg(msg) args = [Connection(_conn=connection), @@ -232,16 +231,12 @@ cdef class Connection: msg = message._get_msg() - print ("About to block") - retval = dbus_connection_send_with_reply_and_block( self.conn, msg, timeout_milliseconds, &error) - print ("done") - if dbus_error_is_set(&error): raise DBusException, error.message @@ -346,7 +341,7 @@ cdef class Connection: i = 0 child_entries = [] - print ("cchild_entries[0] is %d" % (cchild_entries[0])) + while (cchild_entries[i] != NULL): child_entries.append(cchild_entries[i]) i = i + 1 @@ -607,10 +602,8 @@ cdef class Message: if message_type == MESSAGE_TYPE_METHOD_CALL: self.msg = dbus_message_new_method_call(cservice, path, interface, method) elif message_type == MESSAGE_TYPE_METHOD_RETURN: - print ("Doing this") cmsg = method_call._get_msg() self.msg = dbus_message_new_method_return(cmsg) - print ("Done") elif message_type == MESSAGE_TYPE_SIGNAL: self.msg = dbus_message_new_signal(path, interface, name) elif message_type == MESSAGE_TYPE_ERROR: diff --git a/python/examples/example-client.py b/python/examples/example-client.py index 24906b83..0038b2db 100644 --- a/python/examples/example-client.py +++ b/python/examples/example-client.py @@ -4,6 +4,9 @@ import dbus bus = dbus.Bus() remote_service = bus.get_service("org.designfu.SampleService") -remote_object = remote_service.get_object("/MyObject", "org.designfu.SampleInterface") +remote_object = remote_service.get_object("/SomeObject", + "org.designfu.SampleInterface") -remote_object.HelloWorld("Hello from example-client.py!") +hello_reply = remote_object.HelloWorld("Hello from example-client.py!") + +print (hello_reply) diff --git a/python/examples/example-service.py b/python/examples/example-service.py index eb55af44..88f6b500 100644 --- a/python/examples/example-service.py +++ b/python/examples/example-service.py @@ -6,10 +6,11 @@ import gtk class MyObject(dbus.Object): def __init__(self): service = dbus.Service("org.designfu.SampleService") - dbus.Object("/MyObject", [self.HelloWorld], service) + dbus.Object("/SomeObject", [self.HelloWorld], service) - def HelloWorld(self, arg1): - print ("Hello World!: %s" % (arg1)) + def HelloWorld(self, hello_message): + print (hello_message) + return "Hello from example-service.py" object = MyObject() -- cgit v1.2.1 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. --- ChangeLog | 62 +++ 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 +- doc/TODO | 4 +- doc/dbus-specification.sgml | 16 +- test/break-loader.c | 4 +- .../bad-header-field-alignment.message | 34 ++ .../valid-messages/unknown-header-field.message | 9 +- 12 files changed, 441 insertions(+), 244 deletions(-) create mode 100644 test/data/invalid-messages/bad-header-field-alignment.message diff --git a/ChangeLog b/ChangeLog index 36abf234..58702c2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,65 @@ +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. + 2003-09-25 Seth Nickell * python/dbus.py: 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); diff --git a/doc/TODO b/doc/TODO index 1935ff9f..c70cc929 100644 --- a/doc/TODO +++ b/doc/TODO @@ -90,8 +90,6 @@ - document the auth protocol as a set of states and transitions, and then reimplement it in those terms - - Header fields names are required to be aligned on a 4 byte boundary - at the moment. No alignment should be neccessary. - - dbus_gproxy or dbus_g_proxy? + - The OBJECT_PATH type is not documented in the spec. diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml index a2dd1b13..c772b3e5 100644 --- a/doc/dbus-specification.sgml +++ b/doc/dbus-specification.sgml @@ -265,11 +265,10 @@ - Header fields MUST be aligned to a 4-byte boundary. Header field - names MUST consist of a single byte, possible values of which are - defined below. Following the name, the field MUST have a type code - represented as a single unsigned byte, and then a properly-aligned - value of that type. See for a description of how each type is encoded. If an implementation sees a header field name that it does not understand, it MUST ignore that field. @@ -358,10 +357,9 @@ buffer while keeping data types aligned, the total length of the header must be a multiple of 8 bytes. To achieve this, the header MUST be padded with nul bytes to align its total length on an 8-byte boundary. - The minimum number of padding bytes MUST be used. Because all possible - named fields use at least 8 bytes, implementations can distinguish - padding (which must be less than 8 bytes) from additional named fields - (which must be at least 8 bytes). + The minimum number of padding bytes MUST be used. Because zero is an + invalid field name, implementations can distinguish padding (which must be + zero initialized) from additional named fields. diff --git a/test/break-loader.c b/test/break-loader.c index ebe2606b..3771d7cc 100644 --- a/test/break-loader.c +++ b/test/break-loader.c @@ -287,8 +287,8 @@ randomly_add_one_byte (const DBusString *orig_data, i = random_int_in_range (0, _dbus_string_get_length (mutated)); - _dbus_string_insert_byte (mutated, i, - random_int_in_range (0, 256)); + _dbus_string_insert_bytes (mutated, i, 1, + random_int_in_range (0, 256)); } static void diff --git a/test/data/invalid-messages/bad-header-field-alignment.message b/test/data/invalid-messages/bad-header-field-alignment.message new file mode 100644 index 00000000..75776a37 --- /dev/null +++ b/test/data/invalid-messages/bad-header-field-alignment.message @@ -0,0 +1,34 @@ +## last field incorrectly aligned to 4 bytes + +## VALID_HEADER includes a LENGTH Header and LENGTH Body +VALID_HEADER method_call + +HEADER_FIELD INTERFACE +TYPE STRING +STRING 'org.freedesktop.Foo' + +HEADER_FIELD MEMBER +TYPE STRING +STRING 'Bar' + +HEADER_FIELD UNKNOWN +TYPE STRING +STRING 'a' + +ALIGN 4 + +HEADER_FIELD UNKNOWN +TYPE ARRAY +TYPE BYTE +ALIGN 4 +LENGTH ThisByteArray +START_LENGTH ThisByteArray +BYTE 1 +BYTE 2 +END_LENGTH ThisByteArray + + +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +END_LENGTH Body diff --git a/test/data/valid-messages/unknown-header-field.message b/test/data/valid-messages/unknown-header-field.message index 973def68..ac7d624c 100644 --- a/test/data/valid-messages/unknown-header-field.message +++ b/test/data/valid-messages/unknown-header-field.message @@ -3,9 +3,16 @@ ## VALID_HEADER includes a LENGTH Header and LENGTH Body VALID_HEADER method_call REQUIRED_FIELDS + HEADER_FIELD UNKNOWN +TYPE DICT +LENGTH Dict +START_LENGTH Dict +STRING 'int32' TYPE INT32 -INT32 0xfeeb +INT32 0x12345678 +END_LENGTH Dict + ALIGN 8 END_LENGTH Header START_LENGTH Body -- cgit v1.2.1 From 2b1d98c76bae38c2d6955f68b92919172c8ae53b Mon Sep 17 00:00:00 2001 From: Seth Nickell Date: Thu, 25 Sep 2003 09:34:50 +0000 Subject: 2003-09-25 Seth Nickell * python/examples/example-service.py: Johan notices complete wrong code in example-service, but completely wrong in a way that works exactly the same (!). Johan is confused, how could this possibly work? Example code fails to serve purpose of making things clear. Seth fixes. --- ChangeLog | 10 ++++++++++ python/examples/example-service.py | 11 ++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 58702c2e..6317ef54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2003-09-25 Seth Nickell + + * python/examples/example-service.py: + + Johan notices complete wrong code in example-service, but + completely wrong in a way that works exactly the same (!). + Johan is confused, how could this possibly work? Example + code fails to serve purpose of making things clear. + Seth fixes. + 2003-09-25 Mark McLoughlin * doc/dbus-specification.sgml: don't require header fields diff --git a/python/examples/example-service.py b/python/examples/example-service.py index 88f6b500..79fb009d 100644 --- a/python/examples/example-service.py +++ b/python/examples/example-service.py @@ -3,15 +3,16 @@ import dbus import pygtk import gtk -class MyObject(dbus.Object): - def __init__(self): - service = dbus.Service("org.designfu.SampleService") - dbus.Object("/SomeObject", [self.HelloWorld], service) +class SomeObject(dbus.Object): + def __init__(self, service): + dbus.Object.__init__(self, "/SomeObject", [self.HelloWorld], service) def HelloWorld(self, hello_message): print (hello_message) return "Hello from example-service.py" -object = MyObject() + +service = dbus.Service("org.designfu.SampleService") +object = SomeObject(service) gtk.main() -- cgit v1.2.1 From c9cf30dc373b521cc243d8c75ac21b02a39c73e7 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 25 Sep 2003 13:38:44 +0000 Subject: 2003-09-25 Havoc Pennington * bus/session.conf.in: fix security policy, reported by Seth Nickell --- ChangeLog | 4 ++++ bus/session.conf.in | 6 +++++- doc/TODO | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 6317ef54..dc19e03d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-09-25 Havoc Pennington + + * bus/session.conf.in: fix security policy, reported by Seth Nickell + 2003-09-25 Seth Nickell * python/examples/example-service.py: diff --git a/bus/session.conf.in b/bus/session.conf.in index 45945688..df76d33f 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -13,9 +13,13 @@ @EXPANDED_LIBDIR@/dbus-1.0/services - + + + + diff --git a/doc/TODO b/doc/TODO index c70cc929..f1c8e6aa 100644 --- a/doc/TODO +++ b/doc/TODO @@ -92,4 +92,6 @@ - dbus_gproxy or dbus_g_proxy? + - add dbus_message_has_path(), maybe has_member/interface + - The OBJECT_PATH type is not documented in the spec. -- cgit v1.2.1 From 9f2ff915a181585ddeaca079a7cfe057d10a3aed Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 25 Sep 2003 18:48:03 +0000 Subject: 2003-09-25 Havoc Pennington * bus/session.conf.in: fix my mess --- ChangeLog | 4 ++++ bus/session.conf.in | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index dc19e03d..91c7c195 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-09-25 Havoc Pennington + + * bus/session.conf.in: fix my mess + 2003-09-25 Havoc Pennington * bus/session.conf.in: fix security policy, reported by Seth Nickell diff --git a/bus/session.conf.in b/bus/session.conf.in index df76d33f..34d2492c 100644 --- a/bus/session.conf.in +++ b/bus/session.conf.in @@ -15,7 +15,7 @@ - -- cgit v1.2.1 From c5cf3857b114d0008a6d8191abf389064b5a66fc Mon Sep 17 00:00:00 2001 From: Seth Nickell Date: Fri, 26 Sep 2003 10:27:59 +0000 Subject: 2003-09-26 Seth Nickell * python/dbus.py: * python/examples/example-signals.py: Start implementing some notions of signals. The API is really terrible, but they sort of work (with the exception of being able to filter by service, and to transmit signals *as* a particular service). Need to figure out how to make messages come from the service we registered :-( * python/dbus_bindings.pyx.in: Removed duplicate message_handler callbacks. --- ChangeLog | 16 +++++++++++ python/dbus.py | 55 +++++++++++++++++++++++++++++++++++--- python/dbus_bindings.pyx.in | 50 +++++++++++++++++++--------------- python/examples/example-signals.py | 27 +++++++++++++++++++ 4 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 python/examples/example-signals.py diff --git a/ChangeLog b/ChangeLog index 91c7c195..4f68da09 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2003-09-26 Seth Nickell + + * python/dbus.py: + * python/examples/example-signals.py: + + Start implementing some notions of signals. The API + is really terrible, but they sort of work (with the + exception of being able to filter by service, and to + transmit signals *as* a particular service). Need to + figure out how to make messages come from the service + we registered :-( + + * python/dbus_bindings.pyx.in: + + Removed duplicate message_handler callbacks. + 2003-09-25 Havoc Pennington * bus/session.conf.in: fix my mess diff --git a/python/dbus.py b/python/dbus.py index d09b3fec..c7ab5dd3 100644 --- a/python/dbus.py +++ b/python/dbus.py @@ -56,6 +56,8 @@ class Bus: def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True): self._connection = dbus_bindings.bus_get(bus_type) + self._connection.add_filter(self._signal_func) + self._match_rule_to_receivers = { } if (glib_mainloop): self._connection.setup_with_g_main() @@ -65,10 +67,46 @@ class Bus: """ return RemoteService(self._connection, service_name) + def add_signal_receiver(self, receiver, interface=None, service=None, path=None): + match_rule = self._get_match_rule(interface, service, path) + + if (not self._match_rule_to_receivers.has_key(match_rule)): + self._match_rule_to_receivers[match_rule] = [ ] + self._match_rule_to_receivers[match_rule].append(receiver) + + dbus_bindings.bus_add_match(self._connection, match_rule) + def get_connection(self): """Get the dbus_bindings.Connection object associated with this Bus""" return self._connection + def _get_match_rule(self, interface, service, path): +## if (interface): +## match_rule = match_rule + ",interface='%s'" % (interface) +## if (service): +## match_rule = match_rule + ",service='%s'" % (service) +## if (path): +## match_rule = match_rule + ",path='%s'" % (path) + # FIXME: use the service here too!!! + return "type='signal',interface='%s',path='%s'" % (interface, path) + + def _signal_func(self, connection, message): + if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL): + return + + interface = message.get_interface() + service = message.get_sender() + path = message.get_path() + member = message.get_member() + + match_rule = self._get_match_rule(interface, service, path) + + if (self._match_rule_to_receivers.has_key(match_rule)): + receivers = self._match_rule_to_receivers[match_rule] + args = [interface, member, service, path] + for receiver in receivers: + receiver(*args) + class RemoteObject: """A remote Object. @@ -144,6 +182,10 @@ class Service: """Get the Bus this Service is on""" return self._bus + def get_service_name(self): + """Get the name of this service""" + return self._service_name + class Object: """A base class for exporting your own Objects across the Bus. @@ -161,6 +203,12 @@ class Object: self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb) + def broadcast_signal(self, interface, signal_name): + message = dbus_bindings.Signal(self._object_path, interface, signal_name) + #FIXME: need to set_sender, but it always disconnects when we do this + #message.set_sender(self._service.get_service_name()) + self._connection.send(message) + def _unregister_cb(self, connection): print ("Unregister") @@ -173,9 +221,10 @@ class Object: retval = target_method(*args) except Exception, e: if e.__module__ == '__main__': - error_name = e.__class__ + # FIXME: is it right to use .__name__ here? + error_name = e.__class__.__name__ else: - error_name = e.__module__ + '.' + str(e.__class__) + error_name = e.__module__ + '.' + str(e.__class__.__name__) error_contents = str(e) reply = dbus_bindings.Error(message, error_name, error_contents) else: @@ -193,7 +242,7 @@ class Object: print ('WARNING: registering DBus Object methods, already have a method named %s' % (method.__name__)) method_dict[method.__name__] = method return method_dict - + class RemoteService: """A remote service providing objects. diff --git a/python/dbus_bindings.pyx.in b/python/dbus_bindings.pyx.in index 8feb8678..4ae056c5 100644 --- a/python/dbus_bindings.pyx.in +++ b/python/dbus_bindings.pyx.in @@ -65,7 +65,7 @@ cdef void cunregister_function_handler (DBusConnection *connection, void *user_data): tup = user_data assert (type(tup) == list) - function = tup[0] + function = tup[1] args = [Connection(_conn=connection)] function(*args) @@ -74,7 +74,7 @@ cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection, void *user_data): tup = user_data assert (type(tup) == list) - function = tup[1] + function = tup[0] message = Message(_create=0) message._set_msg(msg) args = [Connection(_conn=connection), @@ -84,20 +84,6 @@ cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection, retval = DBUS_HANDLER_RESULT_HANDLED return retval -cdef DBusHandlerResult chandle_message_function_handler (DBusConnection *connection, - DBusMessage *msg, - void *user_data): - function = user_data - assert (type(function) == function) - messagein = Message(_create=0) - messagein._set_msg(msg) - args = [Connection(_conn=connection), - messagein] - retval = function(*args) - if (retval == None): - retval = DBUS_HANDLER_RESULT_HANDLED - return retval - cdef class Connection: cdef DBusConnection *conn @@ -258,10 +244,14 @@ cdef class Connection: # FIXME: set_dispatch_status_function, get_unix_user, set_unix_user_function - def add_filter(self, function): + def add_filter(self, filter_function): + user_data = [ filter_function ] + global _user_data_references + _user_data_references.append(user_data) + return dbus_connection_add_filter(self.conn, - chandle_message_function_handler, - function, + cmessage_function_handler, + user_data, NULL) @@ -298,7 +288,7 @@ cdef class Connection: cvtable.unregister_function = cunregister_function_handler cvtable.message_function = cmessage_function_handler - user_data = [unregister_cb, message_cb] + user_data = [message_cb, unregister_cb] global _user_data_references _user_data_references.append(user_data) @@ -314,7 +304,7 @@ cdef class Connection: cvtable.unregister_function = cunregister_function_handler cvtable.message_function = cmessage_function_handler - user_data = [unregister_cb, message_cb] + user_data = [message_cb, unregister_cb] global _user_data_references _user_data_references.append(user_data) @@ -906,4 +896,22 @@ def bus_service_exists(connection, service_name): raise DBusException, error.message return retval +def bus_add_match(connection, rule): + cdef DBusError error + dbus_error_init(&error) + + conn = connection._get_conn() + dbus_bus_add_match (conn, rule, &error) + + if dbus_error_is_set(&error): + raise DBusException, error.message + +def bus_remove_match(connection, rule): + cdef DBusError error + dbus_error_init(&error) + conn = connection._get_conn() + dbus_bus_remove_match (conn, rule, &error) + + if dbus_error_is_set(&error): + raise DBusException, error.message diff --git a/python/examples/example-signals.py b/python/examples/example-signals.py new file mode 100644 index 00000000..8e319569 --- /dev/null +++ b/python/examples/example-signals.py @@ -0,0 +1,27 @@ +import pygtk +import gtk + +import dbus + +class SignalFrom(dbus.Object): + def __init__(self, service): + dbus.Object.__init__(self, "/", [], service) + +def signal_to(interface, signal_name, service, path): + print ("Received signal '%s.%s' from '%s%s'" % (interface, signal_name, service, path)) + +bus = dbus.Bus() +bus.add_signal_receiver(signal_to, + "org.designfu.SignalInterface", + "org.designfu.SignalService", + "/") + + +service = dbus.Service("org.designfu.SignalService", bus) +signal_from = SignalFrom(service) + +signal_from.broadcast_signal("org.designfu.SignalInterface", "HelloWorld") + +gtk.main() + + -- cgit v1.2.1 From 626db3fc5c36879186315fcc6de78824a7b75e9b Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 29 Sep 2003 02:55:05 +0000 Subject: 2003-09-28 Havoc Pennington * HACKING: update to reflect new server --- ChangeLog | 4 ++++ HACKING | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4f68da09..ef77996e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-09-28 Havoc Pennington + + * HACKING: update to reflect new server + 2003-09-26 Seth Nickell * python/dbus.py: diff --git a/HACKING b/HACKING index 3bd2e094..1faad127 100644 --- a/HACKING +++ b/HACKING @@ -90,11 +90,12 @@ To make a release of D-BUS, do the following: - once the commit succeeds, "cvs tag DBUS_X_Y_Z" where X_Y_Z map to version X.Y.Z - - check out the "web" module, copy the tarball to - web/content/software/dbus/releases, "cvs add -kb dbus-x.y.z.tar.gz" + - scp your tarball to freedesktop.org server and copy it + to /home/www/twiki/Software/dbus/releases. This should + be possible if you're in group "dbus" - - update web/content/software/dbus/main.in with a pointer to the - tarball + - update the wiki page http://pdx.freedesktop.org/Software/dbus + to list your new release - post to message-bus-list@freedesktop.org announcing the release. -- cgit v1.2.1