diff options
| author | Havoc Pennington <hp@redhat.com> | 2003-09-30 02:33:11 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2003-09-30 02:33:11 +0000 | 
| commit | dfd1292d525d01914141cc86013589c6e0ea9d5c (patch) | |
| tree | fd0c5dd4296d970abcd70f16dd39cca711177df0 /dbus/dbus-connection.c | |
| parent | c30e28fdae3863651cfd7b5d3d0721a1b21a6919 (diff) | |
| parent | 626db3fc5c36879186315fcc6de78824a7b75e9b (diff) | |
2003-09-29  Havoc Pennington  <hp@pobox.com>
	* Merge dbus-object-names branch. To see the entire patch
	do cvs diff -r DBUS_OBJECT_NAMES_BRANCHPOINT -r dbus-object-names,
	it's huuuuge though.
	To revert, I tagged DBUS_BEFORE_OBJECT_NAMES_MERGE.
2003-09-28  Havoc Pennington  <hp@pobox.com>
	* HACKING: update to reflect new server
2003-09-26  Seth Nickell  <seth@gnome.org>
	* 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  <hp@redhat.com>
	* bus/session.conf.in: fix my mess
2003-09-25  Havoc Pennington  <hp@pobox.com>
	* bus/session.conf.in: fix security policy, reported by Seth Nickell
2003-09-25  Seth Nickell  <seth@gnome.org>
	* 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  <mark@skynet.ie>
	* 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  <seth@gnome.org>
	* 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  <seth@gnome.org>
	* 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  <hp@pobox.com>
	* glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement
2003-09-23  Havoc Pennington  <hp@redhat.com>
	* 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  <hp@pobox.com>
	* 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  <hp@redhat.com>
	* glib/dbus-gproxy.c (dbus_gproxy_manager_get): implement
2003-09-21  Seth Nickell  <seth@gnome.org>
        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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	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  <mark@skynet.ie>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* Make Doxygen contented.
2003-09-07  Havoc Pennington  <hp@pobox.com>
	* doc/dbus-specification.sgml: more updates
2003-09-06  Havoc Pennington  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* glib/Makefile.am: rearrange a bunch of files and get "make
	check" framework set up
2003-08-31  Havoc Pennington  <hp@pobox.com>
	* fix build with --disable-tests
2003-08-30  Havoc Pennington  <hp@pobox.com>
	* dbus/dbus-connection.c: purge DBusMessageHandler
	* dbus/dbus-message-handler.c: remove DBusMessageHandler, just
	use callbacks everywhere
2003-08-30  Havoc Pennington  <hp@pobox.com>
	* test/data/valid-config-files/system.d/test.conf: change to
	root for the user so warnings don't get printed
	* dbus/dbus-message.c: add dbus_message_get_path,
	dbus_message_set_path
	* dbus/dbus-object-tree.c (do_test_dispatch): add test of
	dispatching to a path
	* dbus/dbus-string.c (_dbus_string_validate_path): add
	* dbus/dbus-marshal.c (_dbus_demarshal_object_path): implement
	(_dbus_marshal_object_path): implement
	* dbus/dbus-protocol.h (DBUS_HEADER_FIELD_PATH): new header field
	to contain the path to the target object
	(DBUS_HEADER_FIELD_SENDER_SERVICE): rename
	DBUS_HEADER_FIELD_SENDER to explicitly say it's the sender service
2003-08-30  Havoc Pennington  <hp@pobox.com>
	* dbus/dbus-object-tree.c: write tests and fix the discovered bugs
2003-08-29  Havoc Pennington  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* dbus/dbus-internals.h: fix _DBUS_N_GLOBAL_LOCKS
2003-08-28  Havoc Pennington  <hp@pobox.com>
	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  <hp@pobox.com>
        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  <hp@pobox.com>
	* 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 <deny>/<allow> 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  <hp@redhat.com>
	* 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  <hp@pobox.com>
	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
	<deny>/<allow> stuff to match new message naming scheme
	* bus/policy.c: port over
	* bus/config-parser.c: parse new format
2003-08-16  Havoc Pennington  <hp@pobox.com>
	* dbus/dbus-object-registry.c (add_and_remove_objects): remove
	broken assertion
	* glib/dbus-gproxy.c: some hacking
2003-08-15  Havoc Pennington  <hp@redhat.com>
	* 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  <hp@pobox.com>
	* dbus/dbus-connection.c,
	dbus/dbus-pending-call.c: Finish the pending call stuff
2003-08-14  Havoc Pennington  <hp@redhat.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* dbus/dbus-connection.c (dbus_connection_register_object): fix
	build
2003-07-13  Havoc Pennington  <hp@pobox.com>
	* dbus/dbus-object.h (struct DBusObjectVTable): add padding
	fields to DBusObjectVTable and DBusObjectInfo
2003-07-12  Havoc Pennington  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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  <hp@pobox.com>
	* 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-09-28  Havoc Pennington  <hp@pobox.com>
	* real 0.13 release
2003-09-28  Havoc Pennington  <hp@pobox.com>
	* doc/Makefile.am (dbus-specification.html): testing a funky hack
	to work with Debian db2html
2003-09-28  Havoc Pennington  <hp@pobox.com>
	* configure.in: 0.13
	* doc/Makefile.am (dbus-test-plan.html): accept nonexistence of
	stylesheet-images for benefit of Debian
	Change back to using filesystem-linked sockets for the system
	bus, so only root can create the default system bus address.
	* bus/system.conf.in: change to use
	DBUS_SYSTEM_BUS_DEFAULT_ADDRESS
	* dbus/Makefile.am (INCLUDES): remove DBUS_SYSTEM_BUS_PATH define
	from here.
	* configure.in: define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS
	here, and AC_DEFINE DBUS_SYSTEM_PATH
2003-08-09  Anders Carlsson  <andersca@codefactory.se>
	* doc/TODO:
	* doc/busconfig.dtd:
	Add busconfig DTD.
2003-08-09  Anders Carlsson  <andersca@codefactory.se>
	* doc/dbus-specification.sgml:
	Add activation reply values.
2003-08-05  Havoc Pennington  <hp@redhat.com>
	* configure.in: 0.12
2003-08-05  Anders Carlsson  <andersca@codefactory.se>
	* glib/dbus-gmain.c: (watch_fd_new), (watch_fd_ref),
	(watch_fd_unref), (dbus_gsource_check), (dbus_gsource_dispatch),
	(add_watch), (remove_watch), (create_source):
	Refcount fds, fixes some reentrancy issues.
2003-07-30  Havoc Pennington  <hp@redhat.com>
	* dbus/dbus-bus.c (init_connections_unlocked): fix default system
	bus address to be abstract if we have abstract sockets
	* NEWS: update
2003-07-28  Havoc Pennington  <hp@redhat.com>
	* bus/messagebus.in: fix to avoid processname/servicename
	confusion, from Michael Kearey
	https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=100965
2003-07-23  Havoc Pennington  <hp@pobox.com>
	* dbus/dbus-message.c (dbus_message_iter_get_named):
	fix from Andy Hanton to remove broken "+1"
2003-07-16  Havoc Pennington  <hp@pobox.com>
	* tools/dbus-launch.c (babysit): close stdout/stderr in the
	babysitter process, as suggested by Thomas Leonard, so
	an "eval `dbus-launch --exit-with-session`" will actually
	return
2003-07-16  Havoc Pennington  <hp@pobox.com>
	* configure.in: print out EXPANDED_* variables in the summary at
	the end; clean up the code that computes EXPANDED_ variables and
	get the ones using exec_prefix right. Should make things work
	when you build without --prefix
Diffstat (limited to 'dbus/dbus-connection.c')
| -rw-r--r-- | dbus/dbus-connection.c | 1248 | 
1 files changed, 770 insertions, 478 deletions
| diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 01b2a7bf..ed7d57d0 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -31,10 +31,12 @@  #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" +#include "dbus-string.h" +#include "dbus-pending-call.h" +#include "dbus-object-tree.h"  #if 0  #define CONNECTION_LOCK(connection)   do {                      \ @@ -77,7 +79,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().   * @@ -122,8 +124,32 @@   * @{   */ -/** default timeout value when waiting for a message reply */ -#define DEFAULT_TIMEOUT_VALUE (15 * 1000) +/** + * Internal struct representing a message filter function  + */ +typedef struct DBusMessageFilter DBusMessageFilter; + +/** + * Internal struct representing a message filter function  + */ +struct DBusMessageFilter +{ +  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; @@ -157,12 +183,11 @@ 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 */ -  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 */ @@ -180,30 +205,38 @@ struct DBusConnection    DBusList *link_cache; /**< A cache of linked list links to prevent contention                           *   for the global linked list mempool lock                           */ -}; +  DBusObjectTree *objects; /**< Object path handlers 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); +  unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */ +};  static void               _dbus_connection_remove_timeout_locked             (DBusConnection     *connection,                                                                                DBusTimeout        *timeout);  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); +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. @@ -281,7 +314,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; @@ -295,14 +328,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;  	}      } @@ -310,9 +344,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);  } @@ -395,7 +431,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 */ @@ -553,6 +592,118 @@ _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); +} + +/** + * 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 @@ -664,7 +815,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 +823,10 @@ _dbus_connection_new_for_transport (DBusTransport *transport)    DBusList *disconnect_link;    DBusMessage *disconnect_message;    DBusCounter *outgoing_counter; +  DBusObjectTree *objects;    watch_list = NULL;    connection = NULL; -  handler_table = NULL;    pending_replies = NULL;    timeout_list = NULL;    mutex = NULL; @@ -685,6 +836,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,17 +844,12 @@ _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, -			  NULL, (DBusFreeFunction)reply_handler_data_free); +			  NULL, +                          (DBusFreeFunction)free_pending_call_on_hash_removal);    if (pending_replies == NULL)      goto error; @@ -726,7 +873,10 @@ _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_PATH_ORG_FREEDESKTOP_LOCAL, +                                                DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, +                                                "Disconnected"); +      if (disconnect_message == NULL)      goto error; @@ -737,6 +887,10 @@ _dbus_connection_new_for_transport (DBusTransport *transport)    outgoing_counter = _dbus_counter_new ();    if (outgoing_counter == NULL)      goto error; + +  objects = _dbus_object_tree_new (connection); +  if (objects == NULL) +    goto error;    if (_dbus_modify_sigpipe)      _dbus_disable_sigpipe (); @@ -749,11 +903,12 @@ _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;    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); @@ -790,9 +945,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 +956,9 @@ _dbus_connection_new_for_transport (DBusTransport *transport)    if (outgoing_counter)      _dbus_counter_unref (outgoing_counter); + +  if (objects) +    _dbus_object_tree_unref (objects);    return NULL;  } @@ -825,6 +980,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)  { @@ -839,50 +1027,6 @@ _dbus_connection_get_next_client_serial (DBusConnection *connection)  }  /** - * 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) -{ -  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) -    { -      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.   *    * @todo This is basically a hack - we could delete _dbus_transport_handle_watch() @@ -1019,7 +1163,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); @@ -1032,6 +1175,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_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);    dbus_connection_set_unix_user_function (connection, NULL, NULL, NULL); @@ -1043,29 +1188,24 @@ _dbus_connection_last_unref (DBusConnection *connection)    connection->timeouts = NULL;    _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)      { -      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_hash_table_unref (connection->handler_table); -  connection->handler_table = NULL; +  _dbus_object_tree_unref (connection->objects);      _dbus_hash_table_unref (connection->pending_replies);    connection->pending_replies = NULL; @@ -1219,12 +1359,29 @@ dbus_connection_get_is_authenticated (DBusConnection *connection)    return res;  } -struct DBusPreallocatedSend +/** + * 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)  { -  DBusConnection *connection; -  DBusList *queue_link; -  DBusList *counter_link; -}; +  _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) @@ -1350,7 +1507,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); @@ -1398,7 +1557,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, @@ -1407,6 +1571,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 @@ -1430,50 +1616,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); @@ -1483,52 +1660,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 @@ -1538,7 +1692,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.   * @@ -1546,63 +1700,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)      { @@ -1610,17 +1731,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_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); -      reply_handler_data_free (data); +      dbus_pending_call_unref (pending);        return FALSE;      } @@ -1629,33 +1747,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) @@ -1682,45 +1809,34 @@ 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 = 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 @@ -1729,14 +1845,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); @@ -1778,8 +1886,7 @@ dbus_connection_send_with_reply_and_block (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); @@ -1831,11 +1938,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); @@ -1844,6 +1946,70 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,  }  /** + * 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.   *   * @param connection the connection. @@ -1908,6 +2074,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 @@ -1943,6 +2111,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); @@ -1971,6 +2141,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); @@ -2007,7 +2179,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; @@ -2040,6 +2215,25 @@ _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_interface (message_link->data) ? +                 dbus_message_get_interface (message_link->data) : +                 "no interface", +                 connection, connection->n_incoming); +}  /**   * Returns the first-received message from the incoming message queue, @@ -2215,18 +2409,22 @@ 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 + * + * @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   */  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; +  DBusPendingCall *pending;    dbus_int32_t reply_serial;    DBusDispatchStatus status; @@ -2272,11 +2470,11 @@ 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, -						    reply_serial); +  pending = _dbus_hash_table_lookup_int (connection->pending_replies, +                                         reply_serial);    if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy))      { @@ -2294,7 +2492,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 @@ -2305,92 +2503,164 @@ 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_REMOVE_MESSAGE) +      if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)  	break;        link = next;      }    _dbus_list_foreach (&filter_list_copy, -		      (DBusForeachFunction)dbus_message_handler_unref, +		      (DBusForeachFunction)_dbus_message_filter_unref,  		      NULL);    _dbus_list_clear (&filter_list_copy);    CONNECTION_LOCK (connection); +  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) +    goto out; +      /* Did a reply we were waiting on get filtered? */ -  if (reply_handler_data && result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) +  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_REMOVE_MESSAGE) +  if (result == DBUS_HANDLER_RESULT_HANDLED)      goto out; - -  if (reply_handler_data) +   +  if (pending)      { -      CONNECTION_UNLOCK (connection); +      _dbus_pending_call_complete_and_unlock (pending, message); -      _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;      } + +  /* We're still protected from dispatch() reentrancy here +   * since we acquired the dispatcher +   */ +  _dbus_verbose ("  running object path dispatch on message %p (%s)\n", +                 message, +                 dbus_message_get_interface (message) ? +                 dbus_message_get_interface (message) : +                 "no interface"); -  name = dbus_message_get_name (message); -  if (name != NULL) +  result = _dbus_object_tree_dispatch_and_unlock (connection->objects, +                                                  message); +   +  CONNECTION_LOCK (connection); + +  if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) +    goto out; + +  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)      { -      handler = _dbus_hash_table_lookup_string (connection->handler_table, -                                                name); -      if (handler != NULL) +      DBusMessage *reply; +      DBusString str; +      DBusPreallocatedSend *preallocated; + +      _dbus_verbose ("  sending error %s\n", +                     DBUS_ERROR_UNKNOWN_METHOD); +       +      if (!_dbus_string_init (&str))          { -	  /* We're still protected from dispatch() reentrancy here -	   * since we acquired the dispatcher -           */ -	  CONNECTION_UNLOCK (connection); +          result = DBUS_HANDLER_RESULT_NEED_MEMORY; +          goto out; +        } +               +      if (!_dbus_string_append_printf (&str, +                                       "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; +          goto out; +        } +       +      reply = dbus_message_new_error (message, +                                      DBUS_ERROR_UNKNOWN_METHOD, +                                      _dbus_string_get_const_data (&str)); +      _dbus_string_free (&str); -          _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; +      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); +                 dbus_message_get_interface (message) ? +                 dbus_message_get_interface (message) : +                 "no interface", +                 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 +    { +      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 +                                     */ +    } +      _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); @@ -2704,226 +2974,248 @@ 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(). - * 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. + * 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.   * - * 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 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 + * @param function the handler to remove + * @param user_data user data for 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);  }  /** - * 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. + * Registers a handler for a given path in the object hierarchy. + * The given vtable handles messages sent to exactly the given path.   * - * 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 - *  - **/ + * @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_handler (DBusConnection     *connection, -                                  DBusMessageHandler *handler, -                                  const char        **messages_to_handle, -                                  int                 n_messages) +dbus_connection_register_object_path (DBusConnection              *connection, +                                      const char                 **path, +                                      const DBusObjectPathVTable  *vtable, +                                      void                        *user_data)  { -  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); +  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); -  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; -        } +  retval = _dbus_object_tree_register (connection->objects, +                                       FALSE, +                                       path, vtable, +                                       user_data); -      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; -        } +  CONNECTION_UNLOCK (connection); -      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); +  return retval; +} -      ++i; -    } -   -  CONNECTION_UNLOCK (connection); -  return TRUE; +/** + * 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; - failed: -  /* unregister everything registered so far, -   * so we don't fail partially -   */ -  dbus_connection_unregister_handler (connection, -                                      handler, -                                      messages_to_handle, -                                      i); +  _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); -  return FALSE; + +  return retval;  }  /** - * Unregisters a handler for a list of message names. The handlers - * must have been previously registered. + * 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 handler the handler - * @param messages_to_handle the messages to handle - * @param n_messages the number of message names in messages_to_handle - *  - **/ + * @param path the #NULL-terminated array of path elements + */  void -dbus_connection_unregister_handler (DBusConnection     *connection, -                                    DBusMessageHandler *handler, -                                    const char        **messages_to_handle, -                                    int                 n_messages) +dbus_connection_unregister_object_path (DBusConnection              *connection, +                                        const char                 **path)  { -  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); -   +  _dbus_return_if_fail (path != NULL); +  _dbus_return_if_fail (path[0] != 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); -        } +  return _dbus_object_tree_unregister_and_unlock (connection->objects, +                                                  path); +} -      ++i; -    } +/** + * 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_UNLOCK (connection); +  CONNECTION_LOCK (connection); + +  return _dbus_object_tree_list_registered_and_unlock (connection->objects, +                                                       parent_path, +                                                       child_entries);  }  static DBusDataSlotAllocator slot_allocator; | 
