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
This commit is contained in:
Havoc Pennington 2003-09-30 02:33:11 +00:00
commit dfd1292d52
145 changed files with 15672 additions and 3073 deletions

1986
ChangeLog

File diff suppressed because it is too large Load diff

View file

@ -49,7 +49,7 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = dbus bus glib
INPUT = dbus glib
FILE_PATTERNS = *.c *.h
RECURSIVE = YES
#EXCLUDE = test

View file

@ -90,11 +90,12 @@ To make a release of D-BUS, do the following:
- once the commit succeeds, "cvs tag DBUS_X_Y_Z" where
X_Y_Z map to version X.Y.Z
- check out the "web" module, copy the tarball to
web/content/software/dbus/releases, "cvs add -kb dbus-x.y.z.tar.gz"
- scp your tarball to freedesktop.org server and copy it
to /home/www/twiki/Software/dbus/releases. This should
be possible if you're in group "dbus"
- update web/content/software/dbus/main.in with a pointer to the
tarball
- update the wiki page http://pdx.freedesktop.org/Software/dbus
to list your new release
- post to message-bus-list@freedesktop.org announcing the release.

View file

@ -16,8 +16,11 @@ if DBUS_USE_MCS
MONO_SUBDIR=mono
endif
if HAVE_PYTHON
PYTHON_SUBDIR=python
endif
SUBDIRS=dbus bus test doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) tools
SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) $(PYTHON_SUBDIR) test tools
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = dbus-1.pc $(GLIB_PC)

View file

@ -55,3 +55,29 @@ AC_DEFUN(PKG_CHECK_MODULES, [
])
dnl a macro to check for ability to create python extensions
dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
dnl function also defines PYTHON_INCLUDES
AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
[AC_REQUIRE([AM_PATH_PYTHON])
AC_MSG_CHECKING(for headers required to compile python extensions)
dnl deduce PYTHON_INCLUDES
py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
if test "$py_prefix" != "$py_exec_prefix"; then
PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
fi
AC_SUBST(PYTHON_INCLUDES)
dnl check if the headers exist:
save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
AC_TRY_CPP([#include <Python.h>],dnl
[AC_MSG_RESULT(found)
$1],dnl
[AC_MSG_RESULT(not found)
$2])
CPPFLAGS="$save_CPPFLAGS"
])

View file

@ -44,6 +44,8 @@ BUS_SOURCES= \
policy.h \
services.c \
services.h \
signals.c \
signals.h \
test.c \
test.h \
utils.c \

View file

@ -586,7 +586,7 @@ bus_activation_service_created (BusActivation *activation,
if (dbus_connection_get_is_connected (entry->connection))
{
message = dbus_message_new_reply (entry->activation_message);
message = dbus_message_new_method_return (entry->activation_message);
if (!message)
{
BUS_SET_OOM (error);
@ -866,7 +866,7 @@ bus_activation_activate_service (BusActivation *activation,
{
_dbus_verbose ("Service \"%s\" is already active\n", service_name);
message = dbus_message_new_reply (activation_message);
message = dbus_message_new_method_return (activation_message);
if (!message)
{

View file

@ -28,6 +28,7 @@
#include "utils.h"
#include "policy.h"
#include "config-parser.h"
#include "signals.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-internals.h>
@ -44,6 +45,7 @@ struct BusContext
BusActivation *activation;
BusRegistry *registry;
BusPolicy *policy;
BusMatchmaker *matchmaker;
DBusUserDatabase *user_database;
BusLimits limits;
};
@ -505,6 +507,13 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
context->matchmaker = bus_matchmaker_new ();
if (context->matchmaker == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
context->policy = bus_config_parser_steal_policy (parser);
_dbus_assert (context->policy != NULL);
@ -715,6 +724,12 @@ bus_context_unref (BusContext *context)
_dbus_loop_unref (context->loop);
context->loop = NULL;
}
if (context->matchmaker)
{
bus_matchmaker_unref (context->matchmaker);
context->matchmaker = NULL;
}
dbus_free (context->type);
dbus_free (context->address);
@ -771,6 +786,12 @@ bus_context_get_activation (BusContext *context)
return context->activation;
}
BusMatchmaker*
bus_context_get_matchmaker (BusContext *context)
{
return context->matchmaker;
}
DBusLoop*
bus_context_get_loop (BusContext *context)
{
@ -845,18 +866,33 @@ bus_context_get_max_services_per_connection (BusContext *context)
return context->limits.max_services_per_connection;
}
int
bus_context_get_max_match_rules_per_connection (BusContext *context)
{
return context->limits.max_match_rules_per_connection;
}
dbus_bool_t
bus_context_check_security_policy (BusContext *context,
DBusConnection *sender,
DBusConnection *recipient,
DBusConnection *addressed_recipient,
DBusConnection *proposed_recipient,
DBusMessage *message,
DBusError *error)
{
BusClientPolicy *sender_policy;
BusClientPolicy *recipient_policy;
/* NULL sender/receiver means the bus driver */
/* NULL sender, proposed_recipient means the bus driver. NULL
* addressed_recipient means the message didn't specify an explicit
* target. If proposed_recipient is NULL, then addressed_recipient
* is also NULL but is implicitly the bus driver.
*/
_dbus_assert (proposed_recipient == NULL ||
(dbus_message_get_destination (message) == NULL ||
addressed_recipient != NULL));
if (sender != NULL)
{
if (bus_connection_is_active (sender))
@ -869,21 +905,23 @@ bus_context_check_security_policy (BusContext *context,
/* Policy for inactive connections is that they can only send
* the hello message to the bus driver
*/
if (recipient == NULL &&
dbus_message_has_name (message, DBUS_MESSAGE_HELLO))
if (proposed_recipient == NULL &&
dbus_message_is_method_call (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"Hello"))
{
_dbus_verbose ("security check allowing %s message\n",
DBUS_MESSAGE_HELLO);
"Hello");
return TRUE;
}
else
{
_dbus_verbose ("security check disallowing non-%s message\n",
DBUS_MESSAGE_HELLO);
"Hello");
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"Client tried to send a message other than %s without being registered",
DBUS_MESSAGE_HELLO);
"Hello");
return FALSE;
}
@ -895,15 +933,15 @@ bus_context_check_security_policy (BusContext *context,
_dbus_assert ((sender != NULL && sender_policy != NULL) ||
(sender == NULL && sender_policy == NULL));
if (recipient != NULL)
if (proposed_recipient != NULL)
{
/* only the bus driver can send to an inactive recipient (as it
* owns no services, so other apps can't address it). Inactive
* recipients can receive any message.
*/
if (bus_connection_is_active (recipient))
if (bus_connection_is_active (proposed_recipient))
{
recipient_policy = bus_connection_get_policy (recipient);
recipient_policy = bus_connection_get_policy (proposed_recipient);
_dbus_assert (recipient_policy != NULL);
}
else if (sender == NULL)
@ -920,13 +958,13 @@ bus_context_check_security_policy (BusContext *context,
else
recipient_policy = NULL;
_dbus_assert ((recipient != NULL && recipient_policy != NULL) ||
(recipient != NULL && sender == NULL && recipient_policy == NULL) ||
(recipient == NULL && recipient_policy == NULL));
_dbus_assert ((proposed_recipient != NULL && recipient_policy != NULL) ||
(proposed_recipient != NULL && sender == NULL && recipient_policy == NULL) ||
(proposed_recipient == NULL && recipient_policy == NULL));
if (sender_policy &&
!bus_client_policy_check_can_send (sender_policy,
context->registry, recipient,
context->registry, proposed_recipient,
message))
{
const char *dest = dbus_message_get_destination (message);
@ -934,9 +972,14 @@ bus_context_check_security_policy (BusContext *context,
"A security policy in place prevents this sender "
"from sending this message to this recipient, "
"see message bus configuration file (rejected message "
"had name \"%s\" destination \"%s\")",
dbus_message_get_name (message),
dest ? dest : DBUS_SERVICE_DBUS);
"had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")",
dbus_message_get_interface (message) ?
dbus_message_get_interface (message) : "(unset)",
dbus_message_get_member (message) ?
dbus_message_get_member (message) : "(unset)",
dbus_message_get_error_name (message) ?
dbus_message_get_error_name (message) : "(unset)",
dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
_dbus_verbose ("security policy disallowing message due to sender policy\n");
return FALSE;
}
@ -944,6 +987,7 @@ bus_context_check_security_policy (BusContext *context,
if (recipient_policy &&
!bus_client_policy_check_can_receive (recipient_policy,
context->registry, sender,
addressed_recipient, proposed_recipient,
message))
{
const char *dest = dbus_message_get_destination (message);
@ -951,22 +995,29 @@ bus_context_check_security_policy (BusContext *context,
"A security policy in place prevents this recipient "
"from receiving this message from this sender, "
"see message bus configuration file (rejected message "
"had name \"%s\" destination \"%s\")",
dbus_message_get_name (message),
dest ? dest : DBUS_SERVICE_DBUS);
"had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")",
dbus_message_get_interface (message) ?
dbus_message_get_interface (message) : "(unset)",
dbus_message_get_member (message) ?
dbus_message_get_member (message) : "(unset)",
dbus_message_get_error_name (message) ?
dbus_message_get_error_name (message) : "(unset)",
dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
_dbus_verbose ("security policy disallowing message due to recipient policy\n");
return FALSE;
}
/* See if limits on size have been exceeded */
if (recipient &&
dbus_connection_get_outgoing_size (recipient) >
if (proposed_recipient &&
dbus_connection_get_outgoing_size (proposed_recipient) >
context->limits.max_outgoing_bytes)
{
const char *dest = dbus_message_get_destination (message);
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"The destination service \"%s\" has a full message queue",
dest ? dest : DBUS_SERVICE_DBUS);
dest ? dest : (proposed_recipient ?
bus_connection_get_name (proposed_recipient) :
DBUS_SERVICE_ORG_FREEDESKTOP_DBUS));
_dbus_verbose ("security policy disallowing message due to full message queue\n");
return FALSE;
}

View file

@ -40,7 +40,8 @@ typedef struct BusPolicyRule BusPolicyRule;
typedef struct BusRegistry BusRegistry;
typedef struct BusService BusService;
typedef struct BusTransaction BusTransaction;
typedef struct BusMatchmaker BusMatchmaker;
typedef struct BusMatchRule BusMatchRule;
typedef struct
{
@ -54,40 +55,44 @@ typedef struct
int max_connections_per_user; /**< Max number of connections auth'd as same user */
int max_pending_activations; /**< Max number of pending activations for the entire bus */
int max_services_per_connection; /**< Max number of owned services for a single connection */
int max_match_rules_per_connection; /**< Max number of match rules for a single connection */
} BusLimits;
BusContext* bus_context_new (const DBusString *config_file,
dbus_bool_t force_fork,
int print_addr_fd,
int print_pid_fd,
DBusError *error);
void bus_context_shutdown (BusContext *context);
void bus_context_ref (BusContext *context);
void bus_context_unref (BusContext *context);
const char* bus_context_get_type (BusContext *context);
const char* bus_context_get_address (BusContext *context);
BusRegistry* bus_context_get_registry (BusContext *context);
BusConnections* bus_context_get_connections (BusContext *context);
BusActivation* bus_context_get_activation (BusContext *context);
DBusLoop* bus_context_get_loop (BusContext *context);
DBusUserDatabase* bus_context_get_user_database (BusContext *context);
dbus_bool_t bus_context_allow_user (BusContext *context,
unsigned long uid);
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
DBusError *error);
BusContext* bus_context_new (const DBusString *config_file,
dbus_bool_t force_fork,
int print_addr_fd,
int print_pid_fd,
DBusError *error);
void bus_context_shutdown (BusContext *context);
void bus_context_ref (BusContext *context);
void bus_context_unref (BusContext *context);
const char* bus_context_get_type (BusContext *context);
const char* bus_context_get_address (BusContext *context);
BusRegistry* bus_context_get_registry (BusContext *context);
BusConnections* bus_context_get_connections (BusContext *context);
BusActivation* bus_context_get_activation (BusContext *context);
BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
DBusLoop* bus_context_get_loop (BusContext *context);
DBusUserDatabase* bus_context_get_user_database (BusContext *context);
dbus_bool_t bus_context_allow_user (BusContext *context,
unsigned long uid);
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
DBusError *error);
int bus_context_get_activation_timeout (BusContext *context);
int bus_context_get_auth_timeout (BusContext *context);
int bus_context_get_max_completed_connections (BusContext *context);
int bus_context_get_max_incomplete_connections (BusContext *context);
int bus_context_get_max_connections_per_user (BusContext *context);
int bus_context_get_max_pending_activations (BusContext *context);
int bus_context_get_max_services_per_connection (BusContext *context);
int bus_context_get_max_match_rules_per_connection (BusContext *context);
dbus_bool_t bus_context_check_security_policy (BusContext *context,
DBusConnection *sender,
DBusConnection *addressed_recipient,
DBusConnection *proposed_recipient,
DBusMessage *message,
DBusError *error);
int bus_context_get_activation_timeout (BusContext *context);
int bus_context_get_auth_timeout (BusContext *context);
int bus_context_get_max_completed_connections (BusContext *context);
int bus_context_get_max_incomplete_connections (BusContext *context);
int bus_context_get_max_connections_per_user (BusContext *context);
int bus_context_get_max_pending_activations (BusContext *context);
int bus_context_get_max_services_per_connection (BusContext *context);
dbus_bool_t bus_context_check_security_policy (BusContext *context,
DBusConnection *sender,
DBusConnection *recipient,
DBusMessage *message,
DBusError *error);
#endif /* BUS_BUS_H */

View file

@ -88,9 +88,12 @@ typedef struct
} Element;
/**
* Parser for bus configuration file.
*/
struct BusConfigParser
{
int refcount;
int refcount; /**< Reference count */
DBusString basedir; /**< Directory we resolve paths relative to */
@ -331,6 +334,8 @@ bus_config_parser_new (const DBusString *basedir,
parser->limits.max_pending_activations = 256;
parser->limits.max_services_per_connection = 256;
parser->limits.max_match_rules_per_connection = 128;
parser->refcount = 1;
@ -808,6 +813,21 @@ start_busconfig_child (BusConfigParser *parser,
}
}
static int
message_type_from_string (const char *type_str)
{
if (strcmp (type_str, "method_call") == 0)
return DBUS_MESSAGE_TYPE_METHOD_CALL;
if (strcmp (type_str, "method_return") == 0)
return DBUS_MESSAGE_TYPE_METHOD_RETURN;
else if (strcmp (type_str, "signal") == 0)
return DBUS_MESSAGE_TYPE_SIGNAL;
else if (strcmp (type_str, "error") == 0)
return DBUS_MESSAGE_TYPE_ERROR;
else
return DBUS_MESSAGE_TYPE_INVALID;
}
static dbus_bool_t
append_rule_from_element (BusConfigParser *parser,
const char *element_name,
@ -816,11 +836,20 @@ append_rule_from_element (BusConfigParser *parser,
dbus_bool_t allow,
DBusError *error)
{
const char *send;
const char *receive;
const char *send_interface;
const char *send_member;
const char *send_error;
const char *send_destination;
const char *send_path;
const char *send_type;
const char *receive_interface;
const char *receive_member;
const char *receive_error;
const char *receive_sender;
const char *receive_path;
const char *receive_type;
const char *eavesdrop;
const char *own;
const char *send_to;
const char *receive_from;
const char *user;
const char *group;
BusPolicyRule *rule;
@ -829,57 +858,147 @@ append_rule_from_element (BusConfigParser *parser,
attribute_names,
attribute_values,
error,
"send", &send,
"receive", &receive,
"send_interface", &send_interface,
"send_member", &send_member,
"send_error", &send_error,
"send_destination", &send_destination,
"send_path", &send_path,
"send_type", &send_type,
"receive_interface", &receive_interface,
"receive_member", &receive_member,
"receive_error", &receive_error,
"receive_sender", &receive_sender,
"receive_path", &receive_path,
"receive_type", &receive_type,
"eavesdrop", &eavesdrop,
"own", &own,
"send_to", &send_to,
"receive_from", &receive_from,
"user", &user,
"group", &group,
NULL))
return FALSE;
if (!(send || receive || own || send_to || receive_from ||
user || group))
if (!(send_interface || send_member || send_error || send_destination ||
send_type || send_path ||
receive_interface || receive_member || receive_error || receive_sender ||
receive_type || receive_path || eavesdrop ||
own || user || group))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Element <%s> must have one or more attributes",
element_name);
return FALSE;
}
if (((send && own) ||
(send && receive) ||
(send && receive_from) ||
(send && user) ||
(send && group)) ||
((receive && own) ||
(receive && send_to) ||
(receive && user) ||
(receive && group)) ||
((own && send_to) ||
(own && receive_from) ||
(own && user) ||
(own && group)) ||
((send_to && receive_from) ||
(send_to && user) ||
(send_to && group)) ||
((receive_from && user) ||
(receive_from && group)) ||
(user && group))
if ((send_member && (send_interface == NULL && send_path == NULL)) ||
(receive_member && (receive_interface == NULL && receive_path == NULL)))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Invalid combination of attributes on element <%s>, "
"only send/send_to or receive/receive_from may be paired",
"On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.",
element_name);
return FALSE;
}
/* Allowed combinations of elements are:
*
* base, must be all send or all receive:
* nothing
* interface
* interface + member
* error
*
* base send_ can combine with send_destination, send_path, send_type
* base receive_ with receive_sender, receive_path, receive_type, eavesdrop
*
* user, group, own must occur alone
*
* Pretty sure the below stuff is broken, FIXME think about it more.
*/
if (((send_interface && send_error) ||
(send_interface && receive_interface) ||
(send_interface && receive_member) ||
(send_interface && receive_error) ||
(send_interface && receive_sender) ||
(send_interface && eavesdrop) ||
(send_interface && own) ||
(send_interface && user) ||
(send_interface && group)) ||
((send_member && send_error) ||
(send_member && receive_interface) ||
(send_member && receive_member) ||
(send_member && receive_error) ||
(send_member && receive_sender) ||
(send_member && eavesdrop) ||
(send_member && own) ||
(send_member && user) ||
(send_member && group)) ||
((send_error && receive_interface) ||
(send_error && receive_member) ||
(send_error && receive_error) ||
(send_error && receive_sender) ||
(send_error && eavesdrop) ||
(send_error && own) ||
(send_error && user) ||
(send_error && group)) ||
((send_destination && receive_interface) ||
(send_destination && receive_member) ||
(send_destination && receive_error) ||
(send_destination && receive_sender) ||
(send_destination && eavesdrop) ||
(send_destination && own) ||
(send_destination && user) ||
(send_destination && group)) ||
((send_type && receive_interface) ||
(send_type && receive_member) ||
(send_type && receive_error) ||
(send_type && receive_sender) ||
(send_type && eavesdrop) ||
(send_type && own) ||
(send_type && user) ||
(send_type && group)) ||
((send_path && receive_interface) ||
(send_path && receive_member) ||
(send_path && receive_error) ||
(send_path && receive_sender) ||
(send_path && eavesdrop) ||
(send_path && own) ||
(send_path && user) ||
(send_path && group)) ||
((receive_interface && receive_error) ||
(receive_interface && own) ||
(receive_interface && user) ||
(receive_interface && group)) ||
((receive_member && receive_error) ||
(receive_member && own) ||
(receive_member && user) ||
(receive_member && group)) ||
((receive_error && own) ||
(receive_error && user) ||
(receive_error && group)) ||
((eavesdrop && own) ||
(eavesdrop && user) ||
(eavesdrop && group)) ||
((own && user) ||
(own && group)) ||
((user && group)))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Invalid combination of attributes on element <%s>",
element_name);
return FALSE;
}
rule = NULL;
/* In BusPolicyRule, NULL represents wildcard.
@ -887,41 +1006,122 @@ append_rule_from_element (BusConfigParser *parser,
*/
#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
if (send || send_to)
if (send_interface || send_member || send_error || send_destination ||
send_path || send_type)
{
int message_type;
if (IS_WILDCARD (send_interface))
send_interface = NULL;
if (IS_WILDCARD (send_member))
send_member = NULL;
if (IS_WILDCARD (send_error))
send_error = NULL;
if (IS_WILDCARD (send_destination))
send_destination = NULL;
if (IS_WILDCARD (send_path))
send_path = NULL;
if (IS_WILDCARD (send_type))
send_type = NULL;
message_type = DBUS_MESSAGE_TYPE_INVALID;
if (send_type != NULL)
{
message_type = message_type_from_string (send_type);
if (message_type == DBUS_MESSAGE_TYPE_INVALID)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Bad message type \"%s\"",
send_type);
return FALSE;
}
}
rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
if (rule == NULL)
goto nomem;
if (IS_WILDCARD (send))
send = NULL;
if (IS_WILDCARD (send_to))
send_to = NULL;
rule->d.send.message_name = _dbus_strdup (send);
rule->d.send.destination = _dbus_strdup (send_to);
if (send && rule->d.send.message_name == NULL)
rule->d.send.message_type = message_type;
rule->d.send.path = _dbus_strdup (send_path);
rule->d.send.interface = _dbus_strdup (send_interface);
rule->d.send.member = _dbus_strdup (send_member);
rule->d.send.error = _dbus_strdup (send_error);
rule->d.send.destination = _dbus_strdup (send_destination);
if (send_path && rule->d.send.path == NULL)
goto nomem;
if (send_to && rule->d.send.destination == NULL)
if (send_interface && rule->d.send.interface == NULL)
goto nomem;
if (send_member && rule->d.send.member == NULL)
goto nomem;
if (send_error && rule->d.send.error == NULL)
goto nomem;
if (send_destination && rule->d.send.destination == NULL)
goto nomem;
}
else if (receive || receive_from)
else if (receive_interface || receive_member || receive_error || receive_sender ||
receive_path || receive_type || eavesdrop)
{
int message_type;
if (IS_WILDCARD (receive_interface))
receive_interface = NULL;
if (IS_WILDCARD (receive_member))
receive_member = NULL;
if (IS_WILDCARD (receive_error))
receive_error = NULL;
if (IS_WILDCARD (receive_sender))
receive_sender = NULL;
if (IS_WILDCARD (receive_path))
receive_path = NULL;
if (IS_WILDCARD (receive_type))
receive_type = NULL;
message_type = DBUS_MESSAGE_TYPE_INVALID;
if (receive_type != NULL)
{
message_type = message_type_from_string (receive_type);
if (message_type == DBUS_MESSAGE_TYPE_INVALID)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Bad message type \"%s\"",
receive_type);
return FALSE;
}
}
if (eavesdrop &&
!(strcmp (eavesdrop, "true") == 0 ||
strcmp (eavesdrop, "false") == 0))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Bad value \"%s\" for eavesdrop attribute, must be true or false",
eavesdrop);
return FALSE;
}
rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
if (rule == NULL)
goto nomem;
if (IS_WILDCARD (receive))
receive = NULL;
if (IS_WILDCARD (receive_from))
receive_from = NULL;
if (eavesdrop)
rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
rule->d.receive.message_name = _dbus_strdup (receive);
rule->d.receive.origin = _dbus_strdup (receive_from);
if (receive && rule->d.receive.message_name == NULL)
rule->d.receive.message_type = message_type;
rule->d.receive.path = _dbus_strdup (receive_path);
rule->d.receive.interface = _dbus_strdup (receive_interface);
rule->d.receive.member = _dbus_strdup (receive_member);
rule->d.receive.error = _dbus_strdup (receive_error);
rule->d.receive.origin = _dbus_strdup (receive_sender);
if (receive_path && rule->d.receive.path == NULL)
goto nomem;
if (receive_from && rule->d.receive.origin == NULL)
if (receive_interface && rule->d.receive.interface == NULL)
goto nomem;
if (receive_member && rule->d.receive.member == NULL)
goto nomem;
if (receive_error && rule->d.receive.error == NULL)
goto nomem;
if (receive_sender && rule->d.receive.origin == NULL)
goto nomem;
}
else if (own)

View file

@ -25,6 +25,7 @@
#include "policy.h"
#include "services.h"
#include "utils.h"
#include "signals.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.h>
@ -41,6 +42,7 @@ struct BusConnections
BusContext *context;
DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */
DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
int stamp; /**< Incrementing number */
};
static dbus_int32_t connection_data_slot = -1;
@ -52,6 +54,8 @@ typedef struct
DBusConnection *connection;
DBusList *services_owned;
int n_services_owned;
DBusList *match_rules;
int n_match_rules;
char *name;
DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
DBusMessage *oom_message;
@ -60,6 +64,7 @@ typedef struct
long connection_tv_sec; /**< Time when we connected (seconds component) */
long connection_tv_usec; /**< Time when we connected (microsec component) */
int stamp; /**< connections->stamp last time we were traversed */
} BusConnectionData;
static dbus_bool_t expire_incomplete_timeout (void *data);
@ -140,12 +145,20 @@ bus_connection_disconnected (DBusConnection *connection)
{
BusConnectionData *d;
BusService *service;
BusMatchmaker *matchmaker;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
_dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
d->name ? d->name : "(inactive)");
/* Delete our match rules */
if (d->n_match_rules > 0)
{
matchmaker = bus_context_get_matchmaker (d->connections->context);
bus_matchmaker_disconnected (matchmaker, connection);
}
/* Drop any service ownership. FIXME Unfortunately, this requires
* memory allocation and there doesn't seem to be a good way to
@ -881,6 +894,40 @@ bus_connections_get_context (BusConnections *connections)
return connections->context;
}
/*
* This is used to avoid covering the same connection twice when
* traversing connections. Note that it assumes we will
* bus_connection_mark_stamp() each connection at least once per
* INT_MAX increments of the global stamp, or wraparound would break
* things.
*/
void
bus_connections_increment_stamp (BusConnections *connections)
{
connections->stamp += 1;
}
/* Mark connection with current stamp, return TRUE if it
* didn't already have that stamp
*/
dbus_bool_t
bus_connection_mark_stamp (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
if (d->stamp == d->connections->stamp)
return FALSE;
else
{
d->stamp = d->connections->stamp;
return TRUE;
}
}
BusContext*
bus_connection_get_context (DBusConnection *connection)
{
@ -929,6 +976,18 @@ bus_connection_get_activation (DBusConnection *connection)
return bus_context_get_activation (d->connections->context);
}
BusMatchmaker*
bus_connection_get_matchmaker (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
return bus_context_get_matchmaker (d->connections->context);
}
/**
* Checks whether the connection is registered with the message bus.
*
@ -963,19 +1022,19 @@ bus_connection_preallocate_oom_error (DBusConnection *connection)
if (preallocated == NULL)
return FALSE;
/* d->name may be NULL, but that is OK */
message = dbus_message_new (DBUS_ERROR_NO_MEMORY,
d->name);
message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
if (message == NULL)
{
dbus_connection_free_preallocated_send (connection, preallocated);
return FALSE;
}
dbus_message_set_is_error (message, TRUE);
if (!dbus_message_set_sender (message,
DBUS_SERVICE_DBUS))
/* d->name may be NULL, but that is OK */
if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) ||
!dbus_message_set_destination (message, d->name) ||
!dbus_message_set_sender (message,
DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
dbus_connection_free_preallocated_send (connection, preallocated);
dbus_message_unref (message);
@ -1024,6 +1083,62 @@ bus_connection_send_oom_error (DBusConnection *connection,
d->oom_preallocated = NULL;
}
void
bus_connection_add_match_rule_link (DBusConnection *connection,
DBusList *link)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
_dbus_list_append_link (&d->match_rules, link);
d->n_match_rules += 1;
}
dbus_bool_t
bus_connection_add_match_rule (DBusConnection *connection,
BusMatchRule *rule)
{
DBusList *link;
link = _dbus_list_alloc_link (rule);
if (link == NULL)
return FALSE;
bus_connection_add_match_rule_link (connection, link);
return TRUE;
}
void
bus_connection_remove_match_rule (DBusConnection *connection,
BusMatchRule *rule)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
_dbus_list_remove_last (&d->match_rules, rule);
d->n_match_rules -= 1;
_dbus_assert (d->n_match_rules >= 0);
}
int
bus_connection_get_n_match_rules (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
return d->n_match_rules;
}
void
bus_connection_add_owned_service_link (DBusConnection *connection,
DBusList *link)
@ -1092,6 +1207,8 @@ bus_connection_complete (DBusConnection *connection,
_dbus_assert (d != NULL);
_dbus_assert (d->name == NULL);
_dbus_assert (d->policy == NULL);
_dbus_assert (!bus_connection_is_active (connection));
if (!_dbus_string_copy_data (name, &d->name))
{
@ -1147,6 +1264,8 @@ bus_connection_complete (DBusConnection *connection,
/* See if we can remove the timeout */
bus_connections_expire_incomplete (d->connections);
_dbus_assert (bus_connection_is_active (connection));
return TRUE;
}
@ -1312,17 +1431,22 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
* to check security policy since it was not done in
* dispatch.c
*/
_dbus_verbose ("Sending %s from driver\n",
dbus_message_get_name (message));
if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
_dbus_verbose ("Sending %s %s %s from driver\n",
dbus_message_get_interface (message) ?
dbus_message_get_interface (message) : "(no interface)",
dbus_message_get_member (message) ?
dbus_message_get_member (message) : "(no member)",
dbus_message_get_error_name (message) ?
dbus_message_get_error_name (message) : "(no error name)");
if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
return FALSE;
/* If security policy doesn't allow the message, we silently
* eat it; the driver doesn't care about getting a reply.
*/
if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
NULL, connection, message, NULL))
NULL, connection, connection, message, NULL))
return TRUE;
return bus_transaction_send (transaction, connection, message);
@ -1337,11 +1461,16 @@ bus_transaction_send (BusTransaction *transaction,
BusConnectionData *d;
DBusList *link;
_dbus_verbose (" trying to add %s %s to transaction%s\n",
dbus_message_get_is_error (message) ? "error" :
_dbus_verbose (" trying to add %s interface=%s member=%s error=%s to transaction%s\n",
dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" :
dbus_message_get_reply_serial (message) != 0 ? "reply" :
"message",
dbus_message_get_name (message),
dbus_message_get_interface (message) ?
dbus_message_get_interface (message) : "(unset)",
dbus_message_get_member (message) ?
dbus_message_get_member (message) : "(unset)",
dbus_message_get_error_name (message) ?
dbus_message_get_error_name (message) : "(unset)",
dbus_connection_get_is_connected (connection) ?
"" : " (disconnected)");
@ -1550,13 +1679,13 @@ bus_transaction_send_error_reply (BusTransaction *transaction,
_dbus_assert (error != NULL);
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_verbose ("Sending error reply %s \"%s\"\n",
error->name, error->message);
reply = dbus_message_new_error_reply (in_reply_to,
error->name,
error->message);
reply = dbus_message_new_error (in_reply_to,
error->name,
error->message);
if (reply == NULL)
return FALSE;

View file

@ -44,16 +44,18 @@ void bus_connections_foreach_active (BusConnections
BusConnectionForeachFunction function,
void *data);
BusContext* bus_connections_get_context (BusConnections *connections);
void bus_connections_increment_stamp (BusConnections *connections);
BusContext* bus_connection_get_context (DBusConnection *connection);
BusConnections* bus_connection_get_connections (DBusConnection *connection);
BusRegistry* bus_connection_get_registry (DBusConnection *connection);
BusActivation* bus_connection_get_activation (DBusConnection *connection);
BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection);
dbus_bool_t bus_connections_check_limits (BusConnections *connections,
DBusConnection *requesting_completion,
DBusError *error);
void bus_connections_expire_incomplete (BusConnections *connections);
dbus_bool_t bus_connection_mark_stamp (DBusConnection *connection);
dbus_bool_t bus_connection_is_active (DBusConnection *connection);
const char *bus_connection_get_name (DBusConnection *connection);
@ -62,6 +64,15 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
void bus_connection_send_oom_error (DBusConnection *connection,
DBusMessage *in_reply_to);
/* called by signals.c */
dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
BusMatchRule *rule);
void bus_connection_add_match_rule_link (DBusConnection *connection,
DBusList *link);
void bus_connection_remove_match_rule (DBusConnection *connection,
BusMatchRule *rule);
int bus_connection_get_n_match_rules (DBusConnection *connection);
/* called by services.c */
dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection,

View file

@ -328,16 +328,33 @@ in the config file.
.TP
.I "<deny>"
.I "<allow>"
.PP
A <deny> element appears below a <policy> element and prohibits
some action. The possible attributes of a <deny> element are:
A <deny> element appears below a <policy> element and prohibits some
action. The <allow> element makes an exception to previous <deny>
statements, and works just like <deny> but with the inverse meaning.
.PP
The possible attributes of these elements are:
.nf
send="messagename"
receive="messagename"
send_interface="interface_name"
send_member="method_or_signal_name"
send_error="error_name"
send_destination="service_name"
send_type="method_call" | "method_return" | "signal" | "error"
send_path="/path/name"
receive_interface="interface_name"
receive_member="method_or_signal_name"
receive_error="error_name"
receive_sender="service_name"
receive_type="method_call" | "method_return" | "signal" | "error"
receive_path="/path/name"
eavesdrop="true" | "false"
own="servicename"
send_to="servicename"
receive_from="servicename"
user="username"
group="groupname"
.fi
@ -345,11 +362,11 @@ some action. The possible attributes of a <deny> element are:
.PP
Examples:
.nf
<deny send="org.freedesktop.System.Reboot"/>
<deny receive="org.freedesktop.System.Reboot"/>
<deny send_interface="org.freedesktop.System" send_member="Reboot"/>
<deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
<deny own="org.freedesktop.System"/>
<deny send_to="org.freedesktop.System"/>
<deny receive_from="org.freedesktop.System"/>
<deny send_destination="org.freedesktop.System"/>
<deny receive_sender="org.freedesktop.System"/>
<deny user="john"/>
<deny group="enemies"/>
.fi
@ -360,18 +377,38 @@ particular action. If it matches, the action is denied (unless later
rules in the config file allow it).
.PP
send_to and receive_from mean that messages may not be sent to or
received from the *owner* of the given service, not that they may not
be sent *to that service name*. That is, if a connection owns services
A, B, C, and sending to A is denied, sending to B or C will not work
either.
send_destination and receive_sender rules mean that messages may not be
sent to or received from the *owner* of the given service, not that
they may not be sent *to that service name*. That is, if a connection
owns services A, B, C, and sending to A is denied, sending to B or C
will not work either.
.PP
The other send_* and receive_* attributes are purely textual/by-value
matches against the given field in the message header.
.PP
"Eavesdropping" occurs when an application receives a message that
was explicitly addressed to a service the application does not own.
Eavesdropping thus only applies to messages that are addressed to
services (i.e. it does not apply to signals).
.PP
For <allow>, eavesdrop="true" indicates that the rule matches even
when eavesdropping. eavesdrop="false" is the default and means that
the rule only allows messages to go to their specified recipient.
For <deny>, eavesdrop="true" indicates that the rule matches
only when eavesdropping. eavesdrop="false" is the default for <deny>
also, but here it means that the rule applies always, even when
not eavesdropping. The eavesdrop attribute can only be combined with
receive rules (with receive_* attributes).
.PP
user and group denials mean that the given user or group may
not connect to the message bus.
.PP
For "servicename" or "messagename" or "username" or "groupname"
For "service_name", "username", "groupname", etc.
the character "*" can be substituted, meaning "any." Complex globs
like "foo.bar.*" aren't allowed for now because they'd be work to
implement and maybe encourage sloppy security anyway.
@ -382,18 +419,21 @@ for a user or group; user/group denials can only be inside
context="default" or context="mandatory" policies.
.PP
A single <deny> rule may specify both send and send_to, OR both
receive and receive_from. In this case, the denial applies only if
both attributes match the message being denied.
e.g. <deny send="foo.bar" send_to="foo.blah"/> would deny
messages of the given name AND to the given service.
.TP
.I "<allow>"
A single <deny> rule may specify combinations of attributes such as
send_service and send_interface and send_type. In this case, the
denial applies only if both attributes match the message being denied.
e.g. <deny send_interface="foo.bar" send_service="foo.blah"/> would
deny messages of the given interface AND to the given service.
To get an OR effect you specify multiple <deny> rules.
.PP
Makes an exception to previous <deny> statements. Works
just like <deny> but with the inverse meaning.
You can't include both send_ and receive_ attributes on the same
rule, since "whether the message can be sent" and "whether it can be
received" are evaluated separately.
.PP
Be careful with send_interface/receive_interface, because the
interface field in messages is optional.
.SH AUTHOR
See http://www.freedesktop.org/software/dbus/doc/AUTHORS

View file

@ -48,15 +48,19 @@ struct BusDesktopFile
int n_allocated_sections;
};
/**
* Parser for service files.
*/
typedef struct
{
DBusString data;
DBusString data; /**< The data from the file */
BusDesktopFile *desktop_file;
int current_section;
BusDesktopFile *desktop_file; /**< The resulting object */
int current_section; /**< The current section being parsed */
int pos, len;
int line_num;
int pos; /**< Current position */
int len; /**< Length */
int line_num; /**< Current line number */
} BusDesktopFileParser;

File diff suppressed because it is too large Load diff

View file

@ -29,8 +29,9 @@
dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
void bus_dispatch_remove_connection (DBusConnection *connection);
dbus_bool_t bus_dispatch_broadcast_message (BusTransaction *transaction,
dbus_bool_t bus_dispatch_matches (BusTransaction *transaction,
DBusConnection *sender,
DBusConnection *recipient,
DBusMessage *message,
DBusError *error);

View file

@ -27,6 +27,7 @@
#include "driver.h"
#include "dispatch.h"
#include "services.h"
#include "signals.h"
#include "utils.h"
#include <dbus/dbus-string.h>
#include <dbus/dbus-internals.h>
@ -49,15 +50,17 @@ bus_driver_send_service_deleted (const char *service_name,
_dbus_verbose ("sending service deleted: %s\n", service_name);
message = dbus_message_new (DBUS_MESSAGE_SERVICE_DELETED,
DBUS_SERVICE_BROADCAST);
message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ServiceDeleted");
if (message == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) ||
!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
DBUS_TYPE_INVALID))
@ -67,7 +70,7 @@ bus_driver_send_service_deleted (const char *service_name,
return FALSE;
}
retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
dbus_message_unref (message);
return retval;
@ -83,15 +86,17 @@ bus_driver_send_service_created (const char *service_name,
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
message = dbus_message_new (DBUS_MESSAGE_SERVICE_CREATED,
DBUS_SERVICE_BROADCAST);
message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ServiceCreated");
if (message == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
dbus_message_unref (message);
BUS_SET_OOM (error);
@ -107,7 +112,7 @@ bus_driver_send_service_created (const char *service_name,
return FALSE;
}
retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
dbus_message_unref (message);
return retval;
@ -123,15 +128,18 @@ bus_driver_send_service_lost (DBusConnection *connection,
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
message = dbus_message_new (DBUS_MESSAGE_SERVICE_LOST,
bus_connection_get_name (connection));
message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ServiceLost");
if (message == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
if (!dbus_message_append_args (message,
if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
DBUS_TYPE_INVALID))
{
@ -163,8 +171,9 @@ bus_driver_send_service_acquired (DBusConnection *connection,
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
message = dbus_message_new (DBUS_MESSAGE_SERVICE_ACQUIRED,
bus_connection_get_name (connection));
message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ServiceAcquired");
if (message == NULL)
{
@ -172,7 +181,8 @@ bus_driver_send_service_acquired (DBusConnection *connection,
return FALSE;
}
if (!dbus_message_append_args (message,
if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
DBUS_TYPE_INVALID))
{
@ -322,6 +332,7 @@ bus_driver_handle_hello (DBusConnection *connection,
bus_service_set_prohibit_replacement (service, TRUE);
_dbus_assert (bus_connection_is_active (connection));
retval = TRUE;
out_0:
@ -343,7 +354,7 @@ bus_driver_send_welcome_message (DBusConnection *connection,
name = bus_connection_get_name (connection);
_dbus_assert (name != NULL);
welcome = dbus_message_new_reply (hello_message);
welcome = dbus_message_new_method_return (hello_message);
if (welcome == NULL)
{
BUS_SET_OOM (error);
@ -387,7 +398,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
registry = bus_connection_get_registry (connection);
reply = dbus_message_new_reply (message);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
{
BUS_SET_OOM (error);
@ -463,7 +474,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
error))
goto out;
reply = dbus_message_new_reply (message);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
{
BUS_SET_OOM (error);
@ -518,7 +529,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
_dbus_string_init_const (&service_name, name);
service = bus_registry_lookup (registry, &service_name);
reply = dbus_message_new_reply (message);
reply = dbus_message_new_method_return (message);
if (reply == NULL)
{
BUS_SET_OOM (error);
@ -591,6 +602,160 @@ bus_driver_handle_activate_service (DBusConnection *connection,
return retval;
}
static dbus_bool_t
send_ack_reply (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
DBusMessage *reply;
reply = dbus_message_new_method_return (message);
if (reply == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
if (!bus_transaction_send_from_driver (transaction, connection, reply))
{
BUS_SET_OOM (error);
dbus_message_unref (reply);
return FALSE;
}
dbus_message_unref (reply);
return TRUE;
}
static dbus_bool_t
bus_driver_handle_add_match (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
BusMatchRule *rule;
char *text;
DBusString str;
BusMatchmaker *matchmaker;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
text = NULL;
rule = NULL;
if (bus_connection_get_n_match_rules (connection) >=
bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
{
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"Connection \"%s\" is not allowed to add more match rules "
"(increase limits in configuration file if required)",
bus_connection_is_active (connection) ?
bus_connection_get_name (connection) :
"(inactive)");
goto failed;
}
if (!dbus_message_get_args (message, error,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID))
{
_dbus_verbose ("No memory to get arguments to AddMatch\n");
goto failed;
}
_dbus_string_init_const (&str, text);
rule = bus_match_rule_parse (connection, &str, error);
if (rule == NULL)
goto failed;
matchmaker = bus_connection_get_matchmaker (connection);
if (!bus_matchmaker_add_rule (matchmaker, rule))
{
BUS_SET_OOM (error);
goto failed;
}
if (!send_ack_reply (connection, transaction,
message, error))
{
bus_matchmaker_remove_rule (matchmaker, rule);
goto failed;
}
bus_match_rule_unref (rule);
dbus_free (text);
return TRUE;
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
if (rule)
bus_match_rule_unref (rule);
if (text)
dbus_free (text);
return FALSE;
}
static dbus_bool_t
bus_driver_handle_remove_match (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
BusMatchRule *rule;
char *text;
DBusString str;
BusMatchmaker *matchmaker;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
text = NULL;
rule = NULL;
if (!dbus_message_get_args (message, error,
DBUS_TYPE_STRING, &text,
DBUS_TYPE_INVALID))
{
_dbus_verbose ("No memory to get arguments to RemoveMatch\n");
goto failed;
}
_dbus_string_init_const (&str, text);
rule = bus_match_rule_parse (connection, &str, error);
if (rule == NULL)
goto failed;
/* Send the ack before we remove the rule, since the ack is undone
* on transaction cancel, but rule removal isn't.
*/
if (!send_ack_reply (connection, transaction,
message, error))
goto failed;
matchmaker = bus_connection_get_matchmaker (connection);
if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
goto failed;
bus_match_rule_unref (rule);
dbus_free (text);
return TRUE;
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
if (rule)
bus_match_rule_unref (rule);
if (text)
dbus_free (text);
return FALSE;
}
/* For speed it might be useful to sort this in order of
* frequency of use (but doesn't matter with only a few items
* anyhow)
@ -603,11 +768,13 @@ struct
DBusMessage *message,
DBusError *error);
} message_handlers[] = {
{ DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
{ DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
{ DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
{ DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
{ DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
{ "AcquireService", bus_driver_handle_acquire_service },
{ "ActivateService", bus_driver_handle_activate_service },
{ "Hello", bus_driver_handle_hello },
{ "ServiceExists", bus_driver_handle_service_exists },
{ "ListServices", bus_driver_handle_list_services },
{ "AddMatch", bus_driver_handle_add_match },
{ "RemoveMatch", bus_driver_handle_remove_match }
};
dbus_bool_t
@ -620,15 +787,32 @@ bus_driver_handle_message (DBusConnection *connection,
int i;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
_dbus_verbose ("Driver got a message: %s\n",
dbus_message_get_name (message));
name = dbus_message_get_name (message);
sender = dbus_message_get_sender (message);
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
{
_dbus_verbose ("Driver got a non-method-call message, ignoring\n");
return TRUE; /* we just ignore this */
}
_dbus_assert (dbus_message_get_interface (message) != NULL);
_dbus_assert (dbus_message_get_member (message) != NULL);
name = dbus_message_get_member (message);
sender = dbus_message_get_sender (message);
if (strcmp (dbus_message_get_interface (message),
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) != 0)
{
_dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
dbus_message_get_interface (message));
goto unknown;
}
_dbus_verbose ("Driver got a method call: %s\n",
dbus_message_get_member (message));
/* security checks should have kept this from getting here */
_dbus_assert (sender != NULL || strcmp (name, DBUS_MESSAGE_HELLO) == 0);
_dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
if (dbus_message_get_reply_serial (message) == 0)
{
@ -659,11 +843,13 @@ bus_driver_handle_message (DBusConnection *connection,
++i;
}
_dbus_verbose ("No driver handler for %s\n", name);
unknown:
_dbus_verbose ("No driver handler for message \"%s\"\n",
name);
dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
"%s does not understand message %s",
DBUS_SERVICE_DBUS, name);
DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, name);
return FALSE;
}

View file

@ -52,7 +52,11 @@ bus_policy_rule_new (BusPolicyRuleType type,
rule->d.group.gid = DBUS_GID_UNSET;
break;
case BUS_POLICY_RULE_SEND:
rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
break;
case BUS_POLICY_RULE_RECEIVE:
rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
break;
case BUS_POLICY_RULE_OWN:
break;
}
@ -80,11 +84,17 @@ bus_policy_rule_unref (BusPolicyRule *rule)
switch (rule->type)
{
case BUS_POLICY_RULE_SEND:
dbus_free (rule->d.send.message_name);
dbus_free (rule->d.send.path);
dbus_free (rule->d.send.interface);
dbus_free (rule->d.send.member);
dbus_free (rule->d.send.error);
dbus_free (rule->d.send.destination);
break;
case BUS_POLICY_RULE_RECEIVE:
dbus_free (rule->d.receive.message_name);
dbus_free (rule->d.receive.path);
dbus_free (rule->d.receive.interface);
dbus_free (rule->d.receive.member);
dbus_free (rule->d.receive.error);
dbus_free (rule->d.receive.origin);
break;
case BUS_POLICY_RULE_OWN:
@ -680,8 +690,8 @@ bus_client_policy_optimize (BusClientPolicy *policy)
/* The idea here is that if we have:
*
* <allow send="foo"/>
* <deny send="*"/>
* <allow send_interface="foo.bar"/>
* <deny send_interface="*"/>
*
* (for example) the deny will always override the allow. So we
* delete the allow. Ditto for deny followed by allow, etc. This is
@ -713,12 +723,20 @@ bus_client_policy_optimize (BusClientPolicy *policy)
{
case BUS_POLICY_RULE_SEND:
remove_preceding =
rule->d.send.message_name == NULL &&
rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID &&
rule->d.send.path == NULL &&
rule->d.send.interface == NULL &&
rule->d.send.member == NULL &&
rule->d.send.error == NULL &&
rule->d.send.destination == NULL;
break;
case BUS_POLICY_RULE_RECEIVE:
remove_preceding =
rule->d.receive.message_name == NULL &&
rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID &&
rule->d.receive.path == NULL &&
rule->d.receive.interface == NULL &&
rule->d.receive.member == NULL &&
rule->d.receive.error == NULL &&
rule->d.receive.origin == NULL;
break;
case BUS_POLICY_RULE_OWN:
@ -791,16 +809,59 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
continue;
}
if (rule->d.send.message_name != NULL)
if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID)
{
if (!dbus_message_has_name (message,
rule->d.send.message_name))
if (dbus_message_get_type (message) != rule->d.send.message_type)
{
_dbus_verbose (" (policy) skipping rule for different message name\n");
_dbus_verbose (" (policy) skipping rule for different message type\n");
continue;
}
}
if (rule->d.send.path != NULL)
{
if (dbus_message_get_path (message) != NULL &&
strcmp (dbus_message_get_path (message),
rule->d.send.path) != 0)
{
_dbus_verbose (" (policy) skipping rule for different path\n");
continue;
}
}
if (rule->d.send.interface != NULL)
{
if (dbus_message_get_interface (message) != NULL &&
strcmp (dbus_message_get_interface (message),
rule->d.send.interface) != 0)
{
_dbus_verbose (" (policy) skipping rule for different interface\n");
continue;
}
}
if (rule->d.send.member != NULL)
{
if (dbus_message_get_member (message) != NULL &&
strcmp (dbus_message_get_member (message),
rule->d.send.member) != 0)
{
_dbus_verbose (" (policy) skipping rule for different member\n");
continue;
}
}
if (rule->d.send.error != NULL)
{
if (dbus_message_get_error_name (message) != NULL &&
strcmp (dbus_message_get_error_name (message),
rule->d.send.error) != 0)
{
_dbus_verbose (" (policy) skipping rule for different error name\n");
continue;
}
}
if (rule->d.send.destination != NULL)
{
/* receiver can be NULL for messages that are sent to the
@ -856,16 +917,33 @@ dbus_bool_t
bus_client_policy_check_can_receive (BusClientPolicy *policy,
BusRegistry *registry,
DBusConnection *sender,
DBusConnection *addressed_recipient,
DBusConnection *proposed_recipient,
DBusMessage *message)
{
DBusList *link;
dbus_bool_t allowed;
dbus_bool_t eavesdropping;
/* NULL sender, proposed_recipient means the bus driver. NULL
* addressed_recipient means the message didn't specify an explicit
* target. If proposed_recipient is NULL, then addressed_recipient
* is also NULL but is implicitly the bus driver.
*/
_dbus_assert (proposed_recipient == NULL ||
(dbus_message_get_destination (message) == NULL ||
addressed_recipient != NULL));
eavesdropping =
(proposed_recipient == NULL || /* explicitly to bus driver */
(addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */
/* policy->rules is in the order the rules appeared
* in the config file, i.e. last rule that applies wins
*/
_dbus_verbose (" (policy) checking receive rules\n");
_dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
allowed = FALSE;
link = _dbus_list_get_first_link (&policy->rules);
@ -873,12 +951,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
{
BusPolicyRule *rule = link->data;
link = _dbus_list_get_next_link (&policy->rules, link);
/* Rule is skipped if it specifies a different
* message name from the message, or a different
* origin from the message
*/
link = _dbus_list_get_next_link (&policy->rules, link);
if (rule->type != BUS_POLICY_RULE_RECEIVE)
{
@ -886,16 +959,77 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
continue;
}
if (rule->d.receive.message_name != NULL)
if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID)
{
if (!dbus_message_has_name (message,
rule->d.receive.message_name))
if (dbus_message_get_type (message) != rule->d.receive.message_type)
{
_dbus_verbose (" (policy) skipping rule for different message name\n");
_dbus_verbose (" (policy) skipping rule for different message type\n");
continue;
}
}
/* for allow, eavesdrop=false means the rule doesn't apply when
* eavesdropping. eavesdrop=true means always allow.
*/
if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
{
_dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
continue;
}
/* for deny, eavesdrop=true means the rule applies only when
* eavesdropping; eavesdrop=false means always deny.
*/
if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
{
_dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
continue;
}
if (rule->d.receive.path != NULL)
{
if (dbus_message_get_path (message) != NULL &&
strcmp (dbus_message_get_path (message),
rule->d.receive.path) != 0)
{
_dbus_verbose (" (policy) skipping rule for different path\n");
continue;
}
}
if (rule->d.receive.interface != NULL)
{
if (dbus_message_get_interface (message) != NULL &&
strcmp (dbus_message_get_interface (message),
rule->d.receive.interface) != 0)
{
_dbus_verbose (" (policy) skipping rule for different interface\n");
continue;
}
}
if (rule->d.receive.member != NULL)
{
if (dbus_message_get_member (message) != NULL &&
strcmp (dbus_message_get_member (message),
rule->d.receive.member) != 0)
{
_dbus_verbose (" (policy) skipping rule for different member\n");
continue;
}
}
if (rule->d.receive.error != NULL)
{
if (dbus_message_get_error_name (message) != NULL &&
strcmp (dbus_message_get_error_name (message),
rule->d.receive.error) != 0)
{
_dbus_verbose (" (policy) skipping rule for different error name\n");
continue;
}
}
if (rule->d.receive.origin != NULL)
{
/* sender can be NULL for messages that originate from the
@ -937,7 +1071,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
}
}
}
/* Use this rule */
allowed = rule->allow;

View file

@ -54,16 +54,27 @@ struct BusPolicyRule
{
struct
{
/* either can be NULL meaning "any" */
char *message_name;
/* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */
int message_type;
/* any of these can be NULL meaning "any" */
char *path;
char *interface;
char *member;
char *error;
char *destination;
} send;
struct
{
/* either can be NULL meaning "any" */
char *message_name;
/* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */
int message_type;
/* any of these can be NULL meaning "any" */
char *path;
char *interface;
char *member;
char *error;
char *origin;
unsigned int eavesdrop : 1;
} receive;
struct
@ -124,6 +135,8 @@ dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy,
dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy,
BusRegistry *registry,
DBusConnection *sender,
DBusConnection *addressed_recipient,
DBusConnection *proposed_recipient,
DBusMessage *message);
dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy,
DBusConnection *connection,

View file

@ -417,10 +417,14 @@ bus_service_relink (BusService *service,
bus_service_ref (service);
}
/**
* Data used to represent an ownership cancellation in
* a bus transaction.
*/
typedef struct
{
DBusConnection *connection;
BusService *service;
DBusConnection *connection; /**< the connection */
BusService *service; /**< service to cancel ownership of */
} OwnershipCancelData;
static void

View file

@ -13,11 +13,14 @@
<servicedir>@EXPANDED_LIBDIR@/dbus-1.0/services</servicedir>
<policy context="default">
<!-- Allow everything -->
<allow send="*"/>
<allow receive="*"/>
<!-- Allow everything to be sent -->
<allow send_destination="*"/>
<!-- Allow everything to be received -->
<allow eavesdrop="true"/>
<!-- Allow anyone to own anything -->
<allow own="*"/>
<allow user="*"/>
<!-- Allow any user to connect -->
<allow user="*"/>
</policy>
<!-- This is included last so local configuration can override what's

778
bus/signals.c Normal file
View file

@ -0,0 +1,778 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* signals.c Bus signal connection implementation
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "signals.h"
#include "services.h"
#include "utils.h"
struct BusMatchRule
{
int refcount; /**< reference count */
DBusConnection *matches_go_to; /**< Owner of the rule */
unsigned int flags; /**< BusMatchFlags */
int message_type;
char *interface;
char *member;
char *sender;
char *destination;
char *path;
};
BusMatchRule*
bus_match_rule_new (DBusConnection *matches_go_to)
{
BusMatchRule *rule;
rule = dbus_new0 (BusMatchRule, 1);
if (rule == NULL)
return NULL;
rule->refcount = 1;
rule->matches_go_to = matches_go_to;
return rule;
}
void
bus_match_rule_ref (BusMatchRule *rule)
{
_dbus_assert (rule->refcount > 0);
rule->refcount += 1;
}
void
bus_match_rule_unref (BusMatchRule *rule)
{
_dbus_assert (rule->refcount > 0);
rule->refcount -= 1;
if (rule->refcount == 0)
{
dbus_free (rule->interface);
dbus_free (rule->member);
dbus_free (rule->sender);
dbus_free (rule->destination);
dbus_free (rule->path);
dbus_free (rule);
}
}
#ifdef DBUS_ENABLE_VERBOSE_MODE
static char*
match_rule_to_string (BusMatchRule *rule)
{
DBusString str;
char *ret;
if (!_dbus_string_init (&str))
{
char *s;
while ((s = _dbus_strdup ("nomem")) == NULL)
; /* only OK for debug spew... */
return s;
}
if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
{
/* FIXME make type readable */
if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
goto nomem;
}
if (rule->flags & BUS_MATCH_INTERFACE)
{
if (_dbus_string_get_length (&str) > 0)
{
if (!_dbus_string_append (&str, ","))
goto nomem;
}
if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
goto nomem;
}
if (rule->flags & BUS_MATCH_MEMBER)
{
if (_dbus_string_get_length (&str) > 0)
{
if (!_dbus_string_append (&str, ","))
goto nomem;
}
if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
goto nomem;
}
if (rule->flags & BUS_MATCH_PATH)
{
if (_dbus_string_get_length (&str) > 0)
{
if (!_dbus_string_append (&str, ","))
goto nomem;
}
if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
goto nomem;
}
if (rule->flags & BUS_MATCH_SENDER)
{
if (_dbus_string_get_length (&str) > 0)
{
if (!_dbus_string_append (&str, ","))
goto nomem;
}
if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
goto nomem;
}
if (rule->flags & BUS_MATCH_DESTINATION)
{
if (_dbus_string_get_length (&str) > 0)
{
if (!_dbus_string_append (&str, ","))
goto nomem;
}
if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
goto nomem;
}
if (!_dbus_string_steal_data (&str, &ret))
goto nomem;
_dbus_string_free (&str);
return ret;
nomem:
_dbus_string_free (&str);
{
char *s;
while ((s = _dbus_strdup ("nomem")) == NULL)
; /* only OK for debug spew... */
return s;
}
}
#endif /* DBUS_ENABLE_VERBOSE_MODE */
dbus_bool_t
bus_match_rule_set_message_type (BusMatchRule *rule,
int type)
{
rule->flags |= BUS_MATCH_MESSAGE_TYPE;
rule->message_type = type;
return TRUE;
}
dbus_bool_t
bus_match_rule_set_interface (BusMatchRule *rule,
const char *interface)
{
char *new;
_dbus_assert (interface != NULL);
new = _dbus_strdup (interface);
if (new == NULL)
return FALSE;
rule->flags |= BUS_MATCH_INTERFACE;
dbus_free (rule->interface);
rule->interface = new;
return TRUE;
}
dbus_bool_t
bus_match_rule_set_member (BusMatchRule *rule,
const char *member)
{
char *new;
_dbus_assert (member != NULL);
new = _dbus_strdup (member);
if (new == NULL)
return FALSE;
rule->flags |= BUS_MATCH_MEMBER;
dbus_free (rule->member);
rule->member = new;
return TRUE;
}
dbus_bool_t
bus_match_rule_set_sender (BusMatchRule *rule,
const char *sender)
{
char *new;
_dbus_assert (sender != NULL);
new = _dbus_strdup (sender);
if (new == NULL)
return FALSE;
rule->flags |= BUS_MATCH_SENDER;
dbus_free (rule->sender);
rule->sender = new;
return TRUE;
}
dbus_bool_t
bus_match_rule_set_destination (BusMatchRule *rule,
const char *destination)
{
char *new;
_dbus_assert (destination != NULL);
new = _dbus_strdup (destination);
if (new == NULL)
return FALSE;
rule->flags |= BUS_MATCH_DESTINATION;
dbus_free (rule->destination);
rule->destination = new;
return TRUE;
}
dbus_bool_t
bus_match_rule_set_path (BusMatchRule *rule,
const char *path)
{
char *new;
_dbus_assert (path != NULL);
new = _dbus_strdup (path);
if (new == NULL)
return FALSE;
rule->flags |= BUS_MATCH_PATH;
dbus_free (rule->path);
rule->path = new;
return TRUE;
}
/*
* The format is comma-separated with strings quoted with single quotes
* as for the shell (to escape a literal single quote, use '\'').
*
* type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
* path='/bar/foo',destination=':452345-34'
*
*/
BusMatchRule*
bus_match_rule_parse (DBusConnection *matches_go_to,
const DBusString *rule_text,
DBusError *error)
{
BusMatchRule *rule;
rule = bus_match_rule_new (matches_go_to);
if (rule == NULL)
goto oom;
/* FIXME implement for real */
if (!bus_match_rule_set_message_type (rule,
DBUS_MESSAGE_TYPE_SIGNAL))
goto oom;
return rule;
oom:
if (rule)
bus_match_rule_unref (rule);
BUS_SET_OOM (error);
return NULL;
}
struct BusMatchmaker
{
int refcount;
DBusList *all_rules;
};
BusMatchmaker*
bus_matchmaker_new (void)
{
BusMatchmaker *matchmaker;
matchmaker = dbus_new0 (BusMatchmaker, 1);
if (matchmaker == NULL)
return NULL;
matchmaker->refcount = 1;
return matchmaker;
}
void
bus_matchmaker_ref (BusMatchmaker *matchmaker)
{
_dbus_assert (matchmaker->refcount > 0);
matchmaker->refcount += 1;
}
void
bus_matchmaker_unref (BusMatchmaker *matchmaker)
{
_dbus_assert (matchmaker->refcount > 0);
matchmaker->refcount -= 1;
if (matchmaker->refcount == 0)
{
while (matchmaker->all_rules != NULL)
{
BusMatchRule *rule;
rule = matchmaker->all_rules->data;
bus_match_rule_unref (rule);
_dbus_list_remove_link (&matchmaker->all_rules,
matchmaker->all_rules);
}
dbus_free (matchmaker);
}
}
/* The rule can't be modified after it's added. */
dbus_bool_t
bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
BusMatchRule *rule)
{
_dbus_assert (bus_connection_is_active (rule->matches_go_to));
if (!_dbus_list_append (&matchmaker->all_rules, rule))
return FALSE;
if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
{
_dbus_list_remove_last (&matchmaker->all_rules, rule);
return FALSE;
}
bus_match_rule_ref (rule);
#ifdef DBUS_ENABLE_VERBOSE_MODE
{
char *s = match_rule_to_string (rule);
_dbus_verbose ("Added match rule %s to connection %p\n",
s, rule->matches_go_to);
dbus_free (s);
}
#endif
return TRUE;
}
static dbus_bool_t
match_rule_equal (BusMatchRule *a,
BusMatchRule *b)
{
if (a->flags != b->flags)
return FALSE;
if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
a->message_type != b->message_type)
return FALSE;
if ((a->flags & BUS_MATCH_MEMBER) &&
strcmp (a->member, b->member) != 0)
return FALSE;
if ((a->flags & BUS_MATCH_PATH) &&
strcmp (a->path, b->path) != 0)
return FALSE;
if ((a->flags & BUS_MATCH_INTERFACE) &&
strcmp (a->interface, b->interface) != 0)
return FALSE;
if ((a->flags & BUS_MATCH_SENDER) &&
strcmp (a->sender, b->sender) != 0)
return FALSE;
if ((a->flags & BUS_MATCH_DESTINATION) &&
strcmp (a->destination, b->destination) != 0)
return FALSE;
return TRUE;
}
static void
bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
DBusList *link)
{
BusMatchRule *rule = link->data;
bus_connection_remove_match_rule (rule->matches_go_to, rule);
_dbus_list_remove_link (&matchmaker->all_rules, link);
#ifdef DBUS_ENABLE_VERBOSE_MODE
{
char *s = match_rule_to_string (rule);
_dbus_verbose ("Removed match rule %s for connection %p\n",
s, rule->matches_go_to);
dbus_free (s);
}
#endif
bus_match_rule_unref (rule);
}
void
bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
BusMatchRule *rule)
{
bus_connection_remove_match_rule (rule->matches_go_to, rule);
_dbus_list_remove (&matchmaker->all_rules, rule);
#ifdef DBUS_ENABLE_VERBOSE_MODE
{
char *s = match_rule_to_string (rule);
_dbus_verbose ("Removed match rule %s for connection %p\n",
s, rule->matches_go_to);
dbus_free (s);
}
#endif
bus_match_rule_unref (rule);
}
/* Remove a single rule which is equal to the given rule by value */
dbus_bool_t
bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
BusMatchRule *value,
DBusError *error)
{
/* FIXME this is an unoptimized linear scan */
DBusList *link;
/* we traverse backward because bus_connection_remove_match_rule()
* removes the most-recently-added rule
*/
link = _dbus_list_get_last_link (&matchmaker->all_rules);
while (link != NULL)
{
BusMatchRule *rule;
DBusList *prev;
rule = link->data;
prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
if (match_rule_equal (rule, value))
{
bus_matchmaker_remove_rule_link (matchmaker, link);
break;
}
link = prev;
}
if (link == NULL)
{
dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
"The given match rule wasn't found and can't be removed");
return FALSE;
}
return TRUE;
}
void
bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
DBusConnection *disconnected)
{
DBusList *link;
/* FIXME
*
* This scans all match rules on the bus. We could avoid that
* for the rules belonging to the connection, since we keep
* a list of those; but for the rules that just refer to
* the connection we'd need to do something more elaborate.
*
*/
_dbus_assert (bus_connection_is_active (disconnected));
link = _dbus_list_get_first_link (&matchmaker->all_rules);
while (link != NULL)
{
BusMatchRule *rule;
DBusList *next;
rule = link->data;
next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
if (rule->matches_go_to == disconnected)
{
bus_matchmaker_remove_rule_link (matchmaker, link);
}
else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
{
/* The rule matches to/from a base service, see if it's the
* one being disconnected, since we know this service name
* will never be recycled.
*/
const char *name;
name = bus_connection_get_name (disconnected);
_dbus_assert (name != NULL); /* because we're an active connection */
if (((rule->flags & BUS_MATCH_SENDER) &&
strcmp (rule->sender, name) == 0) ||
((rule->flags & BUS_MATCH_DESTINATION) &&
strcmp (rule->destination, name) == 0))
{
bus_matchmaker_remove_rule_link (matchmaker, link);
}
}
link = next;
}
}
static dbus_bool_t
connection_is_primary_owner (DBusConnection *connection,
const char *service_name)
{
BusService *service;
DBusString str;
BusRegistry *registry;
registry = bus_connection_get_registry (connection);
_dbus_string_init_const (&str, service_name);
service = bus_registry_lookup (registry, &str);
if (service == NULL)
return FALSE; /* Service doesn't exist so connection can't own it. */
return bus_service_get_primary_owner (service) == connection;
}
static dbus_bool_t
match_rule_matches (BusMatchRule *rule,
BusConnections *connections,
DBusConnection *sender,
DBusConnection *addressed_recipient,
DBusMessage *message)
{
/* All features of the match rule are AND'd together,
* so FALSE if any of them don't match.
*/
if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
{
_dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
if (rule->message_type != dbus_message_get_type (message))
return FALSE;
}
if (rule->flags & BUS_MATCH_INTERFACE)
{
const char *iface;
_dbus_assert (rule->interface != NULL);
iface = dbus_message_get_interface (message);
if (iface == NULL)
return FALSE;
if (strcmp (iface, rule->interface) != 0)
return FALSE;
}
if (rule->flags & BUS_MATCH_MEMBER)
{
const char *member;
_dbus_assert (rule->member != NULL);
member = dbus_message_get_member (message);
if (member == NULL)
return FALSE;
if (strcmp (member, rule->member) != 0)
return FALSE;
}
if (rule->flags & BUS_MATCH_SENDER)
{
_dbus_assert (rule->sender != NULL);
if (!connection_is_primary_owner (sender, rule->sender))
return FALSE;
}
if (rule->flags & BUS_MATCH_DESTINATION)
{
const char *destination;
_dbus_assert (rule->destination != NULL);
if (addressed_recipient == NULL)
return FALSE;
destination = dbus_message_get_destination (message);
if (destination == NULL)
return FALSE;
if (!connection_is_primary_owner (addressed_recipient, rule->destination))
return FALSE;
}
if (rule->flags & BUS_MATCH_PATH)
{
const char *path;
_dbus_assert (rule->path != NULL);
path = dbus_message_get_path (message);
if (path == NULL)
return FALSE;
if (strcmp (path, rule->path) != 0)
return FALSE;
}
return TRUE;
}
dbus_bool_t
bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
BusConnections *connections,
DBusConnection *sender,
DBusConnection *addressed_recipient,
DBusMessage *message,
DBusList **recipients_p)
{
/* FIXME for now this is a wholly unoptimized linear search */
/* Guessing the important optimization is to skip the signal-related
* match lists when processing method call and exception messages.
* So separate match rule lists for signals?
*/
DBusList *link;
_dbus_assert (*recipients_p == NULL);
/* This avoids sending same message to the same connection twice.
* Purpose of the stamp instead of a bool is to avoid iterating over
* all connections resetting the bool each time.
*/
bus_connections_increment_stamp (connections);
/* addressed_recipient is already receiving the message, don't add to list.
* NULL addressed_recipient means either bus driver, or this is a signal
* and thus lacks a specific addressed_recipient.
*/
if (addressed_recipient != NULL)
bus_connection_mark_stamp (addressed_recipient);
link = _dbus_list_get_first_link (&matchmaker->all_rules);
while (link != NULL)
{
BusMatchRule *rule;
rule = link->data;
#ifdef DBUS_ENABLE_VERBOSE_MODE
{
char *s = match_rule_to_string (rule);
_dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
s, rule->matches_go_to);
dbus_free (s);
}
#endif
if (match_rule_matches (rule, connections,
sender, addressed_recipient, message))
{
_dbus_verbose ("Rule matched\n");
/* Append to the list if we haven't already */
if (bus_connection_mark_stamp (rule->matches_go_to))
{
if (!_dbus_list_append (recipients_p, rule->matches_go_to))
goto nomem;
}
#ifdef DBUS_ENABLE_VERBOSE_MODE
else
{
_dbus_verbose ("Connection already receiving this message, so not adding again\n");
}
#endif /* DBUS_ENABLE_VERBOSE_MODE */
}
link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
}
return TRUE;
nomem:
_dbus_list_clear (recipients_p);
return FALSE;
}
#ifdef DBUS_BUILD_TESTS
#include "test.h"
dbus_bool_t
bus_signals_test (const DBusString *test_data_dir)
{
BusMatchmaker *matchmaker;
matchmaker = bus_matchmaker_new ();
bus_matchmaker_ref (matchmaker);
bus_matchmaker_unref (matchmaker);
bus_matchmaker_unref (matchmaker);
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */

83
bus/signals.h Normal file
View file

@ -0,0 +1,83 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* signals.h Bus signal connection implementation
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef BUS_SIGNALS_H
#define BUS_SIGNALS_H
#include <dbus/dbus.h>
#include <dbus/dbus-string.h>
#include <dbus/dbus-sysdeps.h>
#include "connection.h"
typedef enum
{
BUS_MATCH_MESSAGE_TYPE = 1 << 0,
BUS_MATCH_INTERFACE = 1 << 1,
BUS_MATCH_MEMBER = 1 << 2,
BUS_MATCH_SENDER = 1 << 3,
BUS_MATCH_DESTINATION = 1 << 4,
BUS_MATCH_PATH = 1 << 5
} BusMatchFlags;
BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to);
void bus_match_rule_ref (BusMatchRule *rule);
void bus_match_rule_unref (BusMatchRule *rule);
dbus_bool_t bus_match_rule_set_message_type (BusMatchRule *rule,
int type);
dbus_bool_t bus_match_rule_set_interface (BusMatchRule *rule,
const char *interface);
dbus_bool_t bus_match_rule_set_member (BusMatchRule *rule,
const char *member);
dbus_bool_t bus_match_rule_set_sender (BusMatchRule *rule,
const char *sender);
dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule,
const char *destination);
dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule,
const char *path);
BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to,
const DBusString *rule_text,
DBusError *error);
BusMatchmaker* bus_matchmaker_new (void);
void bus_matchmaker_ref (BusMatchmaker *matchmaker);
void bus_matchmaker_unref (BusMatchmaker *matchmaker);
dbus_bool_t bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
BusMatchRule *rule);
dbus_bool_t bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
BusMatchRule *value,
DBusError *error);
void bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
BusMatchRule *rule);
void bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
DBusConnection *disconnected);
dbus_bool_t bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
BusConnections *connections,
DBusConnection *sender,
DBusConnection *addressed_recipient,
DBusMessage *message,
DBusList **recipients_p);
#endif /* BUS_SIGNALS_H */

View file

@ -34,16 +34,16 @@
<policy context="default">
<!-- Deny everything then punch holes -->
<deny send="*"/>
<deny receive="*"/>
<deny send_interface="*"/>
<deny receive_interface="*"/>
<deny own="*"/>
<!-- But allow all users to connect -->
<allow user="*"/>
<!-- Allow anyone to talk to the message bus -->
<!-- FIXME I think currently these allow rules are always implicit
even if they aren't in here -->
<allow send_to="org.freedesktop.DBus"/>
<allow receive_from="org.freedesktop.DBus"/>
<allow send_destination="org.freedesktop.DBus"/>
<allow receive_sender="org.freedesktop.DBus"/>
</policy>
<!-- Config files are placed here that among other things, punch

View file

@ -89,6 +89,12 @@ main (int argc, char **argv)
check_memleaks (argv[0]);
printf ("%s: Running signals test\n", argv[0]);
if (!bus_signals_test (&test_data_dir))
die ("signals");
check_memleaks (argv[0]);
printf ("%s: Running SHA1 connection test\n", argv[0]);
if (!bus_dispatch_sha1_test (&test_data_dir))
die ("sha1");

View file

@ -102,11 +102,15 @@ remove_client_timeout (DBusTimeout *timeout,
}
static DBusHandlerResult
client_disconnect_handler (DBusMessageHandler *handler,
DBusConnection *connection,
DBusMessage *message,
void *user_data)
client_disconnect_filter (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
if (!dbus_message_is_signal (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
"Disconnected"))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
_dbus_verbose ("Removing client %p in disconnect handler\n",
connection);
@ -120,42 +124,19 @@ client_disconnect_handler (DBusMessageHandler *handler,
client_loop = NULL;
}
return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
static dbus_int32_t handler_slot = -1;
static void
free_handler (void *data)
{
DBusMessageHandler *handler = data;
dbus_message_handler_unref (handler);
dbus_connection_free_data_slot (&handler_slot);
return DBUS_HANDLER_RESULT_HANDLED;
}
dbus_bool_t
bus_setup_debug_client (DBusConnection *connection)
{
DBusMessageHandler *disconnect_handler;
const char *to_handle[] = { DBUS_MESSAGE_LOCAL_DISCONNECT };
dbus_bool_t retval;
disconnect_handler = dbus_message_handler_new (client_disconnect_handler,
NULL, NULL);
dbus_bool_t retval;
if (disconnect_handler == NULL)
if (!dbus_connection_add_filter (connection,
client_disconnect_filter,
NULL, NULL))
return FALSE;
if (!dbus_connection_register_handler (connection,
disconnect_handler,
to_handle,
_DBUS_N_ELEMENTS (to_handle)))
{
dbus_message_handler_unref (disconnect_handler);
return FALSE;
}
retval = FALSE;
if (client_loop == NULL)
@ -182,25 +163,15 @@ bus_setup_debug_client (DBusConnection *connection)
if (!_dbus_list_append (&clients, connection))
goto out;
if (!dbus_connection_allocate_data_slot (&handler_slot))
goto out;
/* Set up handler to be destroyed */
if (!dbus_connection_set_data (connection, handler_slot,
disconnect_handler,
free_handler))
{
dbus_connection_free_data_slot (&handler_slot);
goto out;
}
retval = TRUE;
out:
if (!retval)
{
dbus_message_handler_unref (disconnect_handler); /* unregisters it */
dbus_connection_remove_filter (connection,
client_disconnect_filter,
NULL);
dbus_connection_set_watch_functions (connection,
NULL, NULL, NULL, NULL, NULL);

View file

@ -36,6 +36,7 @@ dbus_bool_t bus_dispatch_test (const DBusString *test_data_d
dbus_bool_t bus_dispatch_sha1_test (const DBusString *test_data_dir);
dbus_bool_t bus_policy_test (const DBusString *test_data_dir);
dbus_bool_t bus_config_parser_test (const DBusString *test_data_dir);
dbus_bool_t bus_signals_test (const DBusString *test_data_dir);
dbus_bool_t bus_setup_debug_client (DBusConnection *connection);
void bus_test_clients_foreach (BusConnectionForeachFunction function,
void *data);

View file

@ -24,6 +24,7 @@ AC_HEADER_STDC
AC_ARG_ENABLE(qt, [ --enable-qt enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto)
AC_ARG_ENABLE(glib, [ --enable-glib enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto)
AC_ARG_ENABLE(gtk, [ --enable-gtk enable GTK-requiring executables],enable_gtk=$enableval,enable_gtk=auto)
AC_ARG_ENABLE(tests, [ --enable-tests enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE)
AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
@ -34,6 +35,8 @@ AC_ARG_ENABLE(gcov, [ --enable-gcov compile with coverage p
AC_ARG_ENABLE(abstract-sockets, [ --enable-abstract-sockets use abstract socket namespace (linux only)],enable_abstract_sockets=$enableval,enable_abstract_sockets=auto)
AC_ARG_ENABLE(gcj, [ --enable-gcj build gcj bindings],enable_gcj=$enableval,enable_gcj=no)
AC_ARG_ENABLE(mono, [ --enable-mono build mono bindings],enable_mono=$enableval,enable_mono=no)
AC_ARG_ENABLE(python, [ --enable-python build python bindings],enable_python=$enableval,enable_python=auto)
AC_ARG_WITH(xml, [ --with-xml=[libxml/expat] XML library to use])
AC_ARG_WITH(init-scripts, [ --with-init-scripts=[redhat] Style of init scripts to install])
@ -54,9 +57,11 @@ if test x$enable_verbose_mode = xyes; then
fi
if test x$enable_asserts = xno; then
AC_DEFINE(DBUS_DISABLE_ASSERT,1,[Disable assertion checking])
AC_DEFINE(G_DISABLE_ASSERT,1,[Disable GLib assertion macros])
fi
if test x$enable_checks = xno; then
AC_DEFINE(DBUS_DISABLE_CHECKS,1,[Disable public API sanity checking])
AC_DEFINE(G_DISABLE_CHECKS,1,[Disable GLib public API sanity checking])
fi
#### gcc warning flags
@ -545,7 +550,7 @@ AC_SUBST(DBUS_TEST_CFLAGS)
AC_SUBST(DBUS_TEST_LIBS)
# Glib detection
PKG_CHECK_MODULES(DBUS_GLIB, glib-2.0, have_glib=yes, have_glib=no)
PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0, have_glib=yes, have_glib=no)
PKG_CHECK_MODULES(DBUS_GLIB_THREADS, glib-2.0 gthread-2.0, have_glib_threads=yes, have_glib_threads=no)
if test x$have_glib = xno ; then
@ -570,6 +575,39 @@ AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
AC_SUBST(DBUS_GLIB_THREADS_LIBS)
DBUS_GLIB_TOOL_CFLAGS=$XML_CFLAGS
DBUS_GLIB_TOOL_LIBS=$XML_LIBS
AC_SUBST(DBUS_GLIB_TOOL_CFLAGS)
AC_SUBST(DBUS_GLIB_TOOL_LIBS)
# GTK detection
if test x$have_glib = xno ; then
AC_MSG_WARN([Can't use GTK+ since GLib not enabled])
have_gtk=no
else
PKG_CHECK_MODULES(DBUS_GTK, gtk+-2.0, have_gtk=yes, have_gtk=no)
fi
if test x$have_gtk = xno ; then
AC_MSG_WARN([GTK+ development libraries not found])
fi
if test x$enable_gtk = xyes; then
if test x$have_gtk = xno; then
AC_MSG_ERROR([GTK+ explicitly required, and GTK+ development libraries not found])
fi
fi
if test x$enable_gtk = xno; then
have_gtk=no;
fi
AM_CONDITIONAL(HAVE_GTK, test x$have_gtk = xyes)
dnl Gtk flags
AC_SUBST(DBUS_GTK_CFLAGS)
AC_SUBST(DBUS_GTK_LIBS)
# Qt detection
have_qt=no
AC_MSG_CHECKING([for qglobal.h])
@ -812,6 +850,42 @@ fi
AC_DEFINE_UNQUOTED(DBUS_SESSION_SOCKET_DIR, "$DBUS_SESSION_SOCKET_DIR", [Where per-session bus puts its sockets])
AC_SUBST(DBUS_SESSION_SOCKET_DIR)
# Detect if we can build Python bindings (need python, python headers, and pyrex)
if test x$enable_python = xno; then
have_python=no
else
AC_MSG_NOTICE([Checking to see if we can build Python bindings])
have_python=no
AM_PATH_PYTHON(2.2)
if test -z "$PYTHON" ; then
AC_MSG_WARN([Python not found])
else
AC_CHECK_PROGS(PYREX, pyrexc)
if test -z "$PYREX" ; then
have_pyrex=no
else
have_pyrex=yes
fi
AM_CHECK_PYTHON_HEADERS(have_python_headers=yes,have_python_headers=no)
if test x$have_pyrex = xyes -a x$have_python_headers = xyes ; then
have_python=yes
fi
fi
if test x$have_python = xno ; then
if test x$enable_python = xyes ; then
AC_MSG_ERROR([Building python explicitly requested, but can't build python bindings])
else
AC_MSG_WARN([Couldn't find either Pyrex or the Python headers, not building Python bindings])
fi
fi
fi
AM_CONDITIONAL(HAVE_PYTHON, test x$have_python = xyes)
AC_OUTPUT([
@ -824,6 +898,7 @@ bus/dbus-daemon-1.1
Makefile
dbus/Makefile
glib/Makefile
python/Makefile
qt/Makefile
gcj/Makefile
gcj/org/Makefile
@ -833,6 +908,7 @@ mono/Makefile
bus/Makefile
tools/Makefile
test/Makefile
test/glib/Makefile
doc/Makefile
dbus-1.pc
dbus-glib-1.pc
@ -863,6 +939,7 @@ echo "
cflags: ${CFLAGS}
cppflags: ${CPPFLAGS}
cxxflags: ${CXXFLAGS}
64-bit int: ${DBUS_INT64_TYPE}
Doxygen: ${DOXYGEN}
db2html: ${DB2HTML}"
@ -895,6 +972,8 @@ echo "
Building checks: ${enable_checks}
Building Qt bindings: ${have_qt}
Building GLib bindings: ${have_glib}
Building Python bindings: ${have_python}
Building GTK+ tools: ${have_gtk}
Building X11 code: ${enable_x11}
Building documentation: ${enable_docs}
Using XML parser: ${with_xml}

View file

@ -15,7 +15,7 @@ dbusinclude_HEADERS= \
dbus-macros.h \
dbus-memory.h \
dbus-message.h \
dbus-message-handler.h \
dbus-pending-call.h \
dbus-protocol.h \
dbus-server.h \
dbus-threads.h \
@ -39,8 +39,10 @@ DBUS_LIB_SOURCES= \
dbus-keyring.c \
dbus-keyring.h \
dbus-message.c \
dbus-message-handler.c \
dbus-message-internal.h \
dbus-object-tree.c \
dbus-object-tree.h \
dbus-pending-call.c \
dbus-resources.c \
dbus-resources.h \
dbus-server.c \

View file

@ -25,22 +25,29 @@
#include "dbus-address.h"
#include "dbus-internals.h"
#include "dbus-list.h"
#include "dbus-string.h"
/**
* @defgroup DBusAddress Address parsing
* @ingroup DBus
* @brief Parsing addresses of D-BUS servers.
* @defgroup DBusAddressInternals Address parsing
* @ingroup DBusInternals
* @brief Implementation of parsing addresses of D-BUS servers.
*
* @{
*/
/**
* Internals of DBusAddressEntry
*/
struct DBusAddressEntry
{
DBusString method;
DBusString method; /**< The address type (unix, tcp, etc.) */
DBusList *keys;
DBusList *values;
DBusList *keys; /**< List of keys */
DBusList *values; /**< List of values */
};
/** @} */ /* End of internals */
static void
dbus_address_entry_free (DBusAddressEntry *entry)
{
@ -71,6 +78,13 @@ dbus_address_entry_free (DBusAddressEntry *entry)
dbus_free (entry);
}
/**
* @defgroup DBusAddress Address parsing
* @ingroup DBus
* @brief Parsing addresses of D-BUS servers.
*
* @{
*/
/**
* Frees a #NULL-terminated array of address entries.
@ -371,7 +385,7 @@ dbus_parse_address (const char *address,
}
/** @} */
/** @} */ /* End of public API */
#ifdef DBUS_BUILD_TESTS
#include "dbus-test.h"

View file

@ -28,8 +28,6 @@
#include "dbus-sha.h"
#include "dbus-userdb.h"
/* See doc/dbus-sasl-profile.txt */
/**
* @defgroup DBusAuth Authentication
* @ingroup DBusInternals
@ -75,10 +73,13 @@ typedef dbus_bool_t (* DBusProcessAuthCommandFunction) (DBusAuth *auth,
const DBusString *command,
const DBusString *args);
/**
* Handler for a given auth protocol command
*/
typedef struct
{
const char *command;
DBusProcessAuthCommandFunction func;
const char *command; /**< Name of the command */
DBusProcessAuthCommandFunction func; /**< Function to handle the command */
} DBusAuthCommandHandler;
/**
@ -113,18 +114,21 @@ typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth,
*/
typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth);
/**
* Virtual table representing a particular auth mechanism.
*/
typedef struct
{
const char *mechanism;
DBusAuthDataFunction server_data_func;
DBusAuthEncodeFunction server_encode_func;
DBusAuthDecodeFunction server_decode_func;
DBusAuthShutdownFunction server_shutdown_func;
DBusInitialResponseFunction client_initial_response_func;
DBusAuthDataFunction client_data_func;
DBusAuthEncodeFunction client_encode_func;
DBusAuthDecodeFunction client_decode_func;
DBusAuthShutdownFunction client_shutdown_func;
const char *mechanism; /**< Name of the mechanism */
DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */
DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */
DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */
DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */
DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */
DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */
DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */
DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */
DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */
} DBusAuthMechanismHandler;
/**
@ -174,17 +178,23 @@ struct DBusAuth
unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
};
/**
* "Subclass" of DBusAuth for client side
*/
typedef struct
{
DBusAuth base;
DBusAuth base; /**< Parent class */
DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */
} DBusAuthClient;
/**
* "Subclass" of DBusAuth for server side.
*/
typedef struct
{
DBusAuth base;
DBusAuth base; /**< Parent class */
int failures; /**< Number of times client has been rejected */
int max_failures; /**< Number of times we reject before disconnect */
@ -2370,7 +2380,7 @@ process_test_subdir (const DBusString *test_base_dir,
goto failed;
}
printf ("Testing:\n");
printf ("Testing %s:\n", subdir);
next:
while (_dbus_directory_get_next_file (dir, &filename, &error))

View file

@ -25,6 +25,7 @@
#include "dbus-bus.h"
#include "dbus-protocol.h"
#include "dbus-internals.h"
#include "dbus-message.h"
#include <string.h>
/**
@ -52,6 +53,10 @@
* Block of message-bus-related data we attach to each
* #DBusConnection used with these convenience functions.
*
*
* @todo get rid of most of these; they should be done
* with DBusGProxy and the Qt equivalent, i.e. the same
* way any other interface would be used.
*/
typedef struct
{
@ -338,6 +343,12 @@ dbus_bus_get (DBusBusType type,
_DBUS_UNLOCK (bus);
return NULL;
}
/* By default we're bound to the lifecycle of
* the message bus.
*/
dbus_connection_set_exit_on_disconnect (connection,
TRUE);
if (!dbus_bus_register (connection, error))
{
@ -403,9 +414,10 @@ dbus_bus_register (DBusConnection *connection,
return TRUE;
}
message = dbus_message_new (DBUS_MESSAGE_HELLO,
DBUS_SERVICE_DBUS);
message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"Hello");
if (!message)
{
@ -521,9 +533,10 @@ dbus_bus_acquire_service (DBusConnection *connection,
_dbus_return_val_if_fail (service_name != NULL, 0);
_dbus_return_val_if_error_is_set (error, 0);
message = dbus_message_new (DBUS_MESSAGE_ACQUIRE_SERVICE,
DBUS_SERVICE_DBUS);
message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"AcquireService");
if (message == NULL)
{
@ -595,8 +608,10 @@ dbus_bus_service_exists (DBusConnection *connection,
_dbus_return_val_if_fail (service_name != NULL, FALSE);
_dbus_return_val_if_error_is_set (error, FALSE);
message = dbus_message_new (DBUS_MESSAGE_SERVICE_EXISTS,
DBUS_SERVICE_DBUS);
message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ServiceExists");
if (message == NULL)
{
_DBUS_SET_OOM (error);
@ -657,8 +672,10 @@ dbus_bus_activate_service (DBusConnection *connection,
DBusMessage *msg;
DBusMessage *reply;
msg = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE,
DBUS_SERVICE_DBUS);
msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"ActivateService");
if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name,
DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID))
@ -669,7 +686,7 @@ dbus_bus_activate_service (DBusConnection *connection,
}
reply = dbus_connection_send_with_reply_and_block (connection, msg,
-1, error);
-1, error);
dbus_message_unref (msg);
if (reply == NULL)
@ -698,5 +715,125 @@ dbus_bus_activate_service (DBusConnection *connection,
return TRUE;
}
static void
send_no_return_values (DBusConnection *connection,
DBusMessage *msg,
DBusError *error)
{
if (error)
{
/* Block to check success codepath */
DBusMessage *reply;
reply = dbus_connection_send_with_reply_and_block (connection, msg,
-1, error);
if (reply == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return;
}
if (dbus_set_error_from_message (error, reply))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
dbus_message_unref (reply);
return;
}
dbus_message_unref (reply);
}
else
{
/* Silently-fail nonblocking codepath */
if (!dbus_connection_send (connection, msg, NULL))
return;
}
}
/**
* Adds a match rule to match messages going through the message bus.
* The "rule" argument is the string form of a match rule.
*
* If you pass #NULL for the error, this function will not
* block; the match thus won't be added until you flush the
* connection, and if there's an error adding the match
* (only possible error is lack of resources in the bus),
* you won't find out about it.
*
* If you pass non-#NULL for the error this function will
* block until it gets a reply.
*
* Normal API conventions would have the function return
* a boolean value indicating whether the error was set,
* but that would require blocking always to determine
* the return value.
*
* @param connection connection to the message bus
* @param rule textual form of match rule
* @param error location to store any errors
*/
void
dbus_bus_add_match (DBusConnection *connection,
const char *rule,
DBusError *error)
{
DBusMessage *msg;
msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"AddMatch");
if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule,
DBUS_TYPE_INVALID))
{
dbus_message_unref (msg);
_DBUS_SET_OOM (error);
return;
}
send_no_return_values (connection, msg, error);
dbus_message_unref (msg);
}
/**
* Removes a previously-added match rule "by value" (the most
* recently-added identical rule gets removed). The "rule" argument
* is the string form of a match rule.
*
* If you pass #NULL for the error, this function will not
* block; otherwise it will. See detailed explanation in
* docs for dbus_bus_add_match().
*
* @param connection connection to the message bus
* @param rule textual form of match rule
* @param error location to store any errors
*/
void
dbus_bus_remove_match (DBusConnection *connection,
const char *rule,
DBusError *error)
{
DBusMessage *msg;
msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
"RemoveMatch");
if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule,
DBUS_TYPE_INVALID))
{
dbus_message_unref (msg);
_DBUS_SET_OOM (error);
return;
}
send_no_return_values (connection, msg, error);
dbus_message_unref (msg);
}
/** @} */

View file

@ -59,6 +59,13 @@ dbus_bool_t dbus_bus_activate_service (DBusConnection *connection,
dbus_uint32_t *reply,
DBusError *error);
void dbus_bus_add_match (DBusConnection *connection,
const char *rule,
DBusError *error);
void dbus_bus_remove_match (DBusConnection *connection,
const char *rule,
DBusError *error);
DBUS_END_DECLS;
#endif /* DBUS_BUS_H */

View file

@ -29,6 +29,8 @@
#include <dbus/dbus-transport.h>
#include <dbus/dbus-resources.h>
#include <dbus/dbus-list.h>
#include <dbus/dbus-timeout.h>
#include <dbus/dbus-dataslot.h>
DBUS_BEGIN_DECLS;
@ -39,9 +41,13 @@ typedef enum
DBUS_ITERATION_BLOCK = 1 << 2 /**< Block if nothing to do. */
} DBusIterationFlags;
/** default timeout value when waiting for a message reply */
#define _DBUS_DEFAULT_TIMEOUT_VALUE (15 * 1000)
void _dbus_connection_lock (DBusConnection *connection);
void _dbus_connection_unlock (DBusConnection *connection);
void _dbus_connection_ref_unlocked (DBusConnection *connection);
void _dbus_connection_unref_unlocked (DBusConnection *connection);
dbus_bool_t _dbus_connection_queue_received_message (DBusConnection *connection,
DBusMessage *message);
void _dbus_connection_queue_received_message_link (DBusConnection *connection,
@ -72,16 +78,52 @@ void _dbus_connection_do_iteration (DBusConnection
unsigned int flags,
int timeout_milliseconds);
void _dbus_connection_notify_disconnected (DBusConnection *connection);
void _dbus_connection_handler_destroyed_locked (DBusConnection *connection,
DBusMessageHandler *handler);
dbus_bool_t _dbus_message_handler_add_connection (DBusMessageHandler *handler,
DBusConnection *connection);
void _dbus_message_handler_remove_connection (DBusMessageHandler *handler,
DBusConnection *connection);
DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandler *handler,
DBusConnection *connection,
DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection,
int timeout_milliseconds,
DBusTimeoutHandler timeout_handler);
void _dbus_pending_call_notify (DBusPendingCall *pending);
void _dbus_connection_remove_pending_call (DBusConnection *connection,
DBusPendingCall *pending);
DBusMessage* _dbus_connection_block_for_reply (DBusConnection *connection,
dbus_uint32_t client_serial,
int timeout_milliseconds);
void _dbus_pending_call_complete_and_unlock (DBusPendingCall *pending,
DBusMessage *message);
/**
* @addtogroup DBusPendingCallInternals DBusPendingCall implementation details
* @{
*/
/**
* @brief Internals of DBusPendingCall
*
* Object representing a reply message that we're waiting for.
*/
struct DBusPendingCall
{
DBusAtomic refcount; /**< reference count */
DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */
DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */
DBusConnection *connection; /**< Connections we're associated with */
DBusMessage *reply; /**< Reply (after we've received it) */
DBusTimeout *timeout; /**< Timeout */
DBusList *timeout_link; /**< Preallocated timeout response */
dbus_uint32_t reply_serial; /**< Expected serial of reply */
unsigned int completed : 1; /**< TRUE if completed */
unsigned int timeout_added : 1; /**< Have added the timeout */
};
/** @} End of DBusPendingCallInternals */
DBUS_END_DECLS;
#endif /* DBUS_CONNECTION_INTERNAL_H */

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-connection.h DBusConnection object
*
* Copyright (C) 2002 Red Hat Inc.
* Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
@ -28,22 +28,17 @@
#define DBUS_CONNECTION_H
#include <dbus/dbus-errors.h>
#include <dbus/dbus-message.h>
#include <dbus/dbus-memory.h>
#include <dbus/dbus-message.h>
DBUS_BEGIN_DECLS;
typedef struct DBusConnection DBusConnection;
typedef struct DBusWatch DBusWatch;
typedef struct DBusTimeout DBusTimeout;
typedef struct DBusMessageHandler DBusMessageHandler;
typedef struct DBusPreallocatedSend DBusPreallocatedSend;
typedef enum
{
DBUS_HANDLER_RESULT_REMOVE_MESSAGE, /**< Remove this message, no further processing. */
DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS /**< Run any additional handlers that are interested in this message. */
} DBusHandlerResult;
typedef struct DBusPendingCall DBusPendingCall;
typedef struct DBusConnection DBusConnection;
typedef struct DBusObjectPathVTable DBusObjectPathVTable;
typedef enum
{
@ -63,6 +58,13 @@ typedef enum
DBUS_DISPATCH_NEED_MEMORY /**< More memory is needed to continue. */
} DBusDispatchStatus;
typedef enum
{
DBUS_HANDLER_RESULT_HANDLED, /**< Message has had its effect */
DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect */
DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory to return another result */
} DBusHandlerResult;
typedef dbus_bool_t (* DBusAddWatchFunction) (DBusWatch *watch,
void *data);
typedef void (* DBusWatchToggledFunction) (DBusWatch *watch,
@ -83,6 +85,14 @@ typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection,
unsigned long uid,
void *data);
typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending,
void *user_data);
typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusConnection *connection,
DBusMessage *message,
void *user_data);
DBusConnection* dbus_connection_open (const char *address,
DBusError *error);
void dbus_connection_ref (DBusConnection *connection);
@ -90,6 +100,8 @@ void dbus_connection_unref (DBusConnection
void dbus_connection_disconnect (DBusConnection *connection);
dbus_bool_t dbus_connection_get_is_connected (DBusConnection *connection);
dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection *connection);
void dbus_connection_set_exit_on_disconnect (DBusConnection *connection,
dbus_bool_t exit_on_disconnect);
void dbus_connection_flush (DBusConnection *connection);
DBusMessage* dbus_connection_borrow_message (DBusConnection *connection);
void dbus_connection_return_message (DBusConnection *connection,
@ -104,7 +116,7 @@ dbus_bool_t dbus_connection_send (DBusConnection
dbus_uint32_t *client_serial);
dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection,
DBusMessage *message,
DBusMessageHandler *reply_handler,
DBusPendingCall **pending_return,
int timeout_milliseconds);
DBusMessage * dbus_connection_send_with_reply_and_block (DBusConnection *connection,
DBusMessage *message,
@ -156,22 +168,18 @@ void dbus_timeout_set_data (DBusTimeout *timeout,
dbus_bool_t dbus_timeout_handle (DBusTimeout *timeout);
dbus_bool_t dbus_timeout_get_enabled (DBusTimeout *timeout);
/* Handlers */
dbus_bool_t dbus_connection_add_filter (DBusConnection *connection,
DBusMessageHandler *handler);
void dbus_connection_remove_filter (DBusConnection *connection,
DBusMessageHandler *handler);
/* Filters */
dbus_bool_t dbus_connection_register_handler (DBusConnection *connection,
DBusMessageHandler *handler,
const char **messages_to_handle,
int n_messages);
void dbus_connection_unregister_handler (DBusConnection *connection,
DBusMessageHandler *handler,
const char **messages_to_handle,
int n_messages);
dbus_bool_t dbus_connection_add_filter (DBusConnection *connection,
DBusHandleMessageFunction function,
void *user_data,
DBusFreeFunction free_data_function);
void dbus_connection_remove_filter (DBusConnection *connection,
DBusHandleMessageFunction function,
void *user_data);
/* Other */
dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p);
void dbus_connection_free_data_slot (dbus_int32_t *slot_p);
dbus_bool_t dbus_connection_set_data (DBusConnection *connection,
@ -200,6 +208,44 @@ void dbus_connection_send_preallocated (DBusConnection
dbus_uint32_t *client_serial);
/* Object tree functionality */
typedef void (* DBusObjectPathUnregisterFunction) (DBusConnection *connection,
void *user_data);
typedef DBusHandlerResult (* DBusObjectPathMessageFunction) (DBusConnection *connection,
DBusMessage *message,
void *user_data);
/**
* Virtual table that must be implemented to handle a portion of the
* object path hierarchy.
*/
struct DBusObjectPathVTable
{
DBusObjectPathUnregisterFunction unregister_function; /**< Function to unregister this handler */
DBusObjectPathMessageFunction message_function; /**< Function to handle messages */
void (* dbus_internal_pad1) (void *); /**< Reserved for future expansion */
void (* dbus_internal_pad2) (void *); /**< Reserved for future expansion */
void (* dbus_internal_pad3) (void *); /**< Reserved for future expansion */
void (* dbus_internal_pad4) (void *); /**< Reserved for future expansion */
};
dbus_bool_t dbus_connection_register_object_path (DBusConnection *connection,
const char **path,
const DBusObjectPathVTable *vtable,
void *user_data);
dbus_bool_t dbus_connection_register_fallback (DBusConnection *connection,
const char **path,
const DBusObjectPathVTable *vtable,
void *user_data);
void dbus_connection_unregister_object_path (DBusConnection *connection,
const char **path);
dbus_bool_t dbus_connection_list_registered (DBusConnection *connection,
const char **parent_path,
char ***child_entries);
DBUS_END_DECLS;
#endif /* DBUS_CONNECTION_H */

View file

@ -40,12 +40,18 @@ struct DBusDataSlot
};
typedef struct DBusAllocatedSlot DBusAllocatedSlot;
/** An allocated slot for storing data
*/
struct DBusAllocatedSlot
{
dbus_int32_t slot_id; /**< ID of this slot */
int refcount; /**< Number of uses of the slot */
};
/**
* An allocator that tracks a set of slot IDs.
*/
struct DBusDataSlotAllocator
{
DBusAllocatedSlot *allocated_slots; /**< Allocated slots */
@ -54,6 +60,10 @@ struct DBusDataSlotAllocator
DBusMutex *lock; /**< thread lock */
};
/**
* Data structure that stores the actual user data set at a given
* slot.
*/
struct DBusDataSlotList
{
DBusDataSlot *slots; /**< Data slots */

View file

@ -23,53 +23,26 @@
*/
#include "dbus-errors.h"
#include "dbus-internals.h"
#include "dbus-string.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
/**
* @defgroup DBusErrors Error reporting
* @ingroup DBus
* @brief Error reporting
*
* Types and functions related to reporting errors.
*
*
* In essence D-BUS error reporting works as follows:
*
* @code
* DBusError error;
* dbus_error_init (&error);
* dbus_some_function (arg1, arg2, &error);
* if (dbus_error_is_set (&error))
* {
* fprintf (stderr, "an error occurred: %s\n", error.message);
* dbus_error_free (&error);
* }
* @endcode
*
* There are some rules. An error passed to a D-BUS function must
* always be unset; you can't pass in an error that's already set. If
* a function has a return code indicating whether an error occurred,
* and also a #DBusError parameter, then the error will always be set
* if and only if the return code indicates an error occurred. i.e.
* the return code and the error are never going to disagree.
*
* An error only needs to be freed if it's been set, not if
* it's merely been initialized.
*
* You can check the specific error that occurred using
* dbus_error_has_name().
*
* @defgroup DBusErrorInternals Error reporting internals
* @ingroup DBusInternals
* @brief Error reporting internals
* @{
*/
/**
* Internals of DBusError
*/
typedef struct
{
const char *name; /**< error name */
char *message; /**< error message */
unsigned int const_message : 1; /** Message is not owned by DBusError */
unsigned int const_message : 1; /**< Message is not owned by DBusError */
unsigned int dummy2 : 1; /**< placeholder */
unsigned int dummy3 : 1; /**< placeholder */
@ -127,6 +100,45 @@ message_from_error (const char *error)
return error;
}
/** @} */ /* End of internals */
/**
* @defgroup DBusErrors Error reporting
* @ingroup DBus
* @brief Error reporting
*
* Types and functions related to reporting errors.
*
*
* In essence D-BUS error reporting works as follows:
*
* @code
* DBusError error;
* dbus_error_init (&error);
* dbus_some_function (arg1, arg2, &error);
* if (dbus_error_is_set (&error))
* {
* fprintf (stderr, "an error occurred: %s\n", error.message);
* dbus_error_free (&error);
* }
* @endcode
*
* There are some rules. An error passed to a D-BUS function must
* always be unset; you can't pass in an error that's already set. If
* a function has a return code indicating whether an error occurred,
* and also a #DBusError parameter, then the error will always be set
* if and only if the return code indicates an error occurred. i.e.
* the return code and the error are never going to disagree.
*
* An error only needs to be freed if it's been set, not if
* it's merely been initialized.
*
* You can check the specific error that occurred using
* dbus_error_has_name().
*
* @{
*/
/**
* Initializes a DBusError structure. Does not allocate
* any memory; the error only needs to be freed
@ -292,9 +304,6 @@ dbus_error_is_set (const DBusError *error)
*
* @todo should be called dbus_error_set()
*
* @todo stdio.h shouldn't be included in this file,
* should write _dbus_string_append_printf instead
*
* @param error the error.
* @param name the error name (not copied!!!)
* @param format printf-style format string.
@ -306,11 +315,9 @@ dbus_set_error (DBusError *error,
...)
{
DBusRealError *real;
DBusString str;
va_list args;
int message_length;
char *message;
char c;
if (error == NULL)
return;
@ -321,31 +328,46 @@ dbus_set_error (DBusError *error,
_dbus_assert (error->name == NULL);
_dbus_assert (error->message == NULL);
if (!_dbus_string_init (&str))
goto nomem;
if (format == NULL)
format = message_from_error (name);
va_start (args, format);
/* Measure the message length */
message_length = vsnprintf (&c, 1, format, args) + 1;
va_end (args);
message = dbus_malloc (message_length);
if (!message)
{
dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL);
return;
if (!_dbus_string_append (&str,
message_from_error (name)))
{
_dbus_string_free (&str);
goto nomem;
}
}
else
{
va_start (args, format);
if (!_dbus_string_append_printf_valist (&str, format, args))
{
_dbus_string_free (&str);
goto nomem;
}
va_end (args);
}
va_start (args, format);
vsprintf (message, format, args);
va_end (args);
real = (DBusRealError *)error;
if (!_dbus_string_steal_data (&str, &real->message))
{
_dbus_string_free (&str);
goto nomem;
}
real->name = name;
real->message = message;
real->const_message = FALSE;
_dbus_string_free (&str);
return;
nomem:
dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL);
}
/** @} */
/** @} */ /* End public API */

View file

@ -35,6 +35,9 @@ DBUS_BEGIN_DECLS;
typedef struct DBusError DBusError;
/**
* Object representing an exception.
*/
struct DBusError
{
const char *name; /**< error name */
@ -50,13 +53,8 @@ struct DBusError
};
#define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed"
#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Activate.ServiceNotFound"
#define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed"
#define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed"
#define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited"
#define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled"
#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed"
#define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory"
#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Error.ServiceNotFound"
#define DBUS_ERROR_SERVICE_DOES_NOT_EXIST "org.freedesktop.DBus.Error.ServiceDoesNotExist"
#define DBUS_ERROR_NO_REPLY "org.freedesktop.DBus.Error.NoReply"
#define DBUS_ERROR_IO_ERROR "org.freedesktop.DBus.Error.IOError"
@ -72,8 +70,14 @@ struct DBusError
#define DBUS_ERROR_DISCONNECTED "org.freedesktop.DBus.Error.Disconnected"
#define DBUS_ERROR_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs"
#define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound"
#define DBUS_ERROR_UNKNOWN_MESSAGE "org.freedesktop.DBus.Error.UnknownMessage"
#define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod"
#define DBUS_ERROR_TIMED_OUT "org.freedesktop.DBus.Error.TimedOut"
#define DBUS_ERROR_MATCH_RULE_NOT_FOUND "org.freedesktop.DBus.Error.MatchRuleNotFound"
#define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed"
#define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed"
#define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited"
#define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled"
#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed"
void dbus_error_init (DBusError *error);
void dbus_error_free (DBusError *error);

View file

@ -221,26 +221,32 @@ typedef struct
int n_entries_on_init; /**< used to detect table resize since initialization */
} DBusRealHashIter;
static DBusHashEntry* find_direct_function (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated);
static DBusHashEntry* find_string_function (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated);
static unsigned int string_hash (const char *str);
static void rebuild_table (DBusHashTable *table);
static DBusHashEntry* alloc_entry (DBusHashTable *table);
static void remove_entry (DBusHashTable *table,
DBusHashEntry **bucket,
DBusHashEntry *entry);
static void free_entry (DBusHashTable *table,
DBusHashEntry *entry);
static void free_entry_data (DBusHashTable *table,
DBusHashEntry *entry);
static DBusHashEntry* find_direct_function (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated);
static DBusHashEntry* find_string_function (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated);
static DBusHashEntry* find_two_strings_function (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated);
static unsigned int string_hash (const char *str);
static unsigned int two_strings_hash (const char *str);
static void rebuild_table (DBusHashTable *table);
static DBusHashEntry* alloc_entry (DBusHashTable *table);
static void remove_entry (DBusHashTable *table,
DBusHashEntry **bucket,
DBusHashEntry *entry);
static void free_entry (DBusHashTable *table,
DBusHashEntry *entry);
static void free_entry_data (DBusHashTable *table,
DBusHashEntry *entry);
/** @} */
@ -323,6 +329,9 @@ _dbus_hash_table_new (DBusHashType type,
case DBUS_HASH_STRING:
table->find_function = find_string_function;
break;
case DBUS_HASH_TWO_STRINGS:
table->find_function = find_two_strings_function;
break;
default:
_dbus_assert_not_reached ("Unknown hash table type");
break;
@ -684,6 +693,24 @@ _dbus_hash_iter_get_string_key (DBusHashIter *iter)
return real->entry->key;
}
/**
* Gets the key for the current entry.
* Only works for hash tables of type #DBUS_HASH_TWO_STRINGS
* @param iter the hash table iterator.
*/
const char*
_dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)
{
DBusRealHashIter *real;
real = (DBusRealHashIter*) iter;
_dbus_assert (real->table != NULL);
_dbus_assert (real->entry != NULL);
return real->entry->key;
}
/**
* A low-level but efficient interface for manipulating the hash
* table. It's efficient because you can get, set, and optionally
@ -803,42 +830,83 @@ add_entry (DBusHashTable *table,
return entry;
}
/* This is g_str_hash from GLib which was
* extensively discussed/tested/profiled
*/
static unsigned int
string_hash (const char *str)
{
register unsigned int result;
register int c;
const char *p = str;
unsigned int h = *p;
/*
* I tried a zillion different hash functions and asked many other
* people for advice. Many people had their own favorite functions,
* all different, but no-one had much idea why they were good ones.
* I chose the one below (multiply by 9 and add new character)
* because of the following reasons:
*
* 1. Multiplying by 10 is perfect for keys that are decimal strings,
* and multiplying by 9 is just about as good.
* 2. Times-9 is (shift-left-3) plus (old). This means that each
* character's bits hang around in the low-order bits of the
* hash value for ever, plus they spread fairly rapidly up to
* the high-order bits to fill out the hash value. This seems
* works well both for decimal and non-decimal strings.
*/
if (h)
for (p += 1; *p != '\0'; p++)
h = (h << 5) - h + *p;
/* FIXME the hash function in GLib is better than this one */
return h;
}
/* This hashes a memory block with two nul-terminated strings
* in it, used in dbus-object-registry.c at the moment.
*/
static unsigned int
two_strings_hash (const char *str)
{
const char *p = str;
unsigned int h = *p;
if (h)
for (p += 1; *p != '\0'; p++)
h = (h << 5) - h + *p;
for (p += 1; *p != '\0'; p++)
h = (h << 5) - h + *p;
result = 0;
while (TRUE)
return h;
}
/** Key comparison function */
typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
static DBusHashEntry*
find_generic_function (DBusHashTable *table,
void *key,
unsigned int idx,
KeyCompareFunc compare_func,
dbus_bool_t create_if_not_found,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated)
{
DBusHashEntry *entry;
if (bucket)
*bucket = NULL;
/* Search all of the entries in this bucket. */
entry = table->buckets[idx];
while (entry != NULL)
{
c = *str;
str++;
if (c == 0)
break;
if ((compare_func == NULL && key == entry->key) ||
(compare_func != NULL && (* compare_func) (key, entry->key) == 0))
{
if (bucket)
*bucket = &(table->buckets[idx]);
if (preallocated)
_dbus_hash_table_free_preallocated_entry (table, preallocated);
return entry;
}
result += (result << 3) + c;
entry = entry->next;
}
if (create_if_not_found)
entry = add_entry (table, idx, key, bucket, preallocated);
else if (preallocated)
_dbus_hash_table_free_preallocated_entry (table, preallocated);
return result;
return entry;
}
static DBusHashEntry*
@ -848,38 +916,47 @@ find_string_function (DBusHashTable *table,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated)
{
DBusHashEntry *entry;
unsigned int idx;
if (bucket)
*bucket = NULL;
idx = string_hash (key) & table->mask;
/* Search all of the entries in this bucket. */
entry = table->buckets[idx];
while (entry != NULL)
{
if (strcmp (key, entry->key) == 0)
{
if (bucket)
*bucket = &(table->buckets[idx]);
return find_generic_function (table, key, idx,
(KeyCompareFunc) strcmp, create_if_not_found, bucket,
preallocated);
}
if (preallocated)
_dbus_hash_table_free_preallocated_entry (table, preallocated);
return entry;
}
entry = entry->next;
}
static int
two_strings_cmp (const char *a,
const char *b)
{
size_t len_a;
size_t len_b;
int res;
res = strcmp (a, b);
if (res != 0)
return res;
if (create_if_not_found)
entry = add_entry (table, idx, key, bucket, preallocated);
else if (preallocated)
_dbus_hash_table_free_preallocated_entry (table, preallocated);
len_a = strlen (a);
len_b = strlen (b);
return entry;
return strcmp (a + len_a + 1, b + len_b + 1);
}
static DBusHashEntry*
find_two_strings_function (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated)
{
unsigned int idx;
idx = two_strings_hash (key) & table->mask;
return find_generic_function (table, key, idx,
(KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,
preallocated);
}
static DBusHashEntry*
@ -889,39 +966,14 @@ find_direct_function (DBusHashTable *table,
DBusHashEntry ***bucket,
DBusPreallocatedHash *preallocated)
{
DBusHashEntry *entry;
unsigned int idx;
if (bucket)
*bucket = NULL;
idx = RANDOM_INDEX (table, key) & table->mask;
/* Search all of the entries in this bucket. */
entry = table->buckets[idx];
while (entry != NULL)
{
if (key == entry->key)
{
if (bucket)
*bucket = &(table->buckets[idx]);
if (preallocated)
_dbus_hash_table_free_preallocated_entry (table, preallocated);
return entry;
}
entry = entry->next;
}
/* Entry not found. Add a new one to the bucket. */
if (create_if_not_found)
entry = add_entry (table, idx, key, bucket, preallocated);
else if (preallocated)
_dbus_hash_table_free_preallocated_entry (table, preallocated);
return entry;
return find_generic_function (table, key, idx,
NULL, create_if_not_found, bucket,
preallocated);
}
static void
@ -1021,6 +1073,9 @@ rebuild_table (DBusHashTable *table)
case DBUS_HASH_STRING:
idx = string_hash (entry->key) & table->mask;
break;
case DBUS_HASH_TWO_STRINGS:
idx = two_strings_hash (entry->key) & table->mask;
break;
case DBUS_HASH_INT:
case DBUS_HASH_ULONG:
case DBUS_HASH_POINTER:
@ -1069,6 +1124,31 @@ _dbus_hash_table_lookup_string (DBusHashTable *table,
return NULL;
}
/**
* Looks up the value for a given string in a hash table
* of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value
* is not present. (A not-present entry is indistinguishable
* from an entry with a value of %NULL.)
* @param table the hash table.
* @param key the string to look up.
* @returns the value of the hash entry.
*/
void*
_dbus_hash_table_lookup_two_strings (DBusHashTable *table,
const char *key)
{
DBusHashEntry *entry;
_dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
if (entry)
return entry->value;
else
return NULL;
}
/**
* Looks up the value for a given integer in a hash table
* of type #DBUS_HASH_INT. Returns %NULL if the value
@ -1175,6 +1255,34 @@ _dbus_hash_table_remove_string (DBusHashTable *table,
return FALSE;
}
/**
* Removes the hash entry for the given key. If no hash entry
* for the key exists, does nothing.
*
* @param table the hash table.
* @param key the hash key.
* @returns #TRUE if the entry existed
*/
dbus_bool_t
_dbus_hash_table_remove_two_strings (DBusHashTable *table,
const char *key)
{
DBusHashEntry *entry;
DBusHashEntry **bucket;
_dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
if (entry)
{
remove_entry (table, bucket, entry);
return TRUE;
}
else
return FALSE;
}
/**
* Removes the hash entry for the given key. If no hash entry
* for the key exists, does nothing.
@ -1296,6 +1404,47 @@ _dbus_hash_table_insert_string (DBusHashTable *table,
return TRUE;
}
/**
* Creates a hash entry with the given key and value.
* The key and value are not copied; they are stored
* in the hash table by reference. If an entry with the
* given key already exists, the previous key and value
* are overwritten (and freed if the hash table has
* a key_free_function and/or value_free_function).
*
* Returns #FALSE if memory for the new hash entry
* can't be allocated.
*
* @param table the hash table.
* @param key the hash entry key.
* @param value the hash entry value.
*/
dbus_bool_t
_dbus_hash_table_insert_two_strings (DBusHashTable *table,
char *key,
void *value)
{
DBusHashEntry *entry;
_dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
if (entry == NULL)
return FALSE; /* no memory */
if (table->free_key_function && entry->key != key)
(* table->free_key_function) (entry->key);
if (table->free_value_function && entry->value != value)
(* table->free_value_function) (entry->value);
entry->key = key;
entry->value = value;
return TRUE;
}
/**
* Creates a hash entry with the given key and value.
* The key and value are not copied; they are stored
@ -1536,6 +1685,28 @@ count_entries (DBusHashTable *table)
return count;
}
/* Copy the foo\0bar\0 double string thing */
static char*
_dbus_strdup2 (const char *str)
{
size_t len;
char *copy;
if (str == NULL)
return NULL;
len = strlen (str);
len += strlen ((str + len + 1));
copy = dbus_malloc (len + 2);
if (copy == NULL)
return NULL;
memcpy (copy, str, len + 2);
return copy;
}
/**
* @ingroup DBusHashTableInternals
* Unit test for DBusHashTable
@ -1548,6 +1719,7 @@ _dbus_hash_test (void)
DBusHashTable *table1;
DBusHashTable *table2;
DBusHashTable *table3;
DBusHashTable *table4;
DBusHashIter iter;
#define N_HASH_KEYS 5000
char **keys;
@ -1569,7 +1741,16 @@ _dbus_hash_test (void)
i = 0;
while (i < N_HASH_KEYS)
{
sprintf (keys[i], "Hash key %d", i);
int len;
/* all the hash keys are TWO_STRINGS, but
* then we can also use those as regular strings.
*/
len = sprintf (keys[i], "Hash key %d", i);
sprintf (keys[i] + len + 1, "Two string %d", i);
_dbus_assert (*(keys[i] + len) == '\0');
_dbus_assert (*(keys[i] + len + 1) != '\0');
++i;
}
printf ("... done.\n");
@ -1588,6 +1769,12 @@ _dbus_hash_test (void)
NULL, dbus_free);
if (table3 == NULL)
goto out;
table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS,
dbus_free, dbus_free);
if (table4 == NULL)
goto out;
/* Insert and remove a bunch of stuff, counting the table in between
* to be sure it's not broken and that iteration works
@ -1624,10 +1811,22 @@ _dbus_hash_test (void)
if (!_dbus_hash_table_insert_ulong (table3,
i, value))
goto out;
key = _dbus_strdup2 (keys[i]);
if (key == NULL)
goto out;
value = _dbus_strdup ("Value!");
if (value == NULL)
goto out;
if (!_dbus_hash_table_insert_two_strings (table4,
key, value))
goto out;
_dbus_assert (count_entries (table1) == i + 1);
_dbus_assert (count_entries (table2) == i + 1);
_dbus_assert (count_entries (table3) == i + 1);
_dbus_assert (count_entries (table4) == i + 1);
value = _dbus_hash_table_lookup_string (table1, keys[i]);
_dbus_assert (value != NULL);
@ -1640,6 +1839,10 @@ _dbus_hash_test (void)
value = _dbus_hash_table_lookup_ulong (table3, i);
_dbus_assert (value != NULL);
_dbus_assert (strcmp (value, keys[i]) == 0);
value = _dbus_hash_table_lookup_two_strings (table4, keys[i]);
_dbus_assert (value != NULL);
_dbus_assert (strcmp (value, "Value!") == 0);
++i;
}
@ -1654,9 +1857,13 @@ _dbus_hash_test (void)
_dbus_hash_table_remove_ulong (table3, i);
_dbus_hash_table_remove_two_strings (table4,
keys[i]);
_dbus_assert (count_entries (table1) == i);
_dbus_assert (count_entries (table2) == i);
_dbus_assert (count_entries (table3) == i);
_dbus_assert (count_entries (table4) == i);
--i;
}
@ -1664,12 +1871,15 @@ _dbus_hash_test (void)
_dbus_hash_table_ref (table1);
_dbus_hash_table_ref (table2);
_dbus_hash_table_ref (table3);
_dbus_hash_table_ref (table4);
_dbus_hash_table_unref (table1);
_dbus_hash_table_unref (table2);
_dbus_hash_table_unref (table3);
_dbus_hash_table_unref (table4);
_dbus_hash_table_unref (table1);
_dbus_hash_table_unref (table2);
_dbus_hash_table_unref (table3);
_dbus_hash_table_unref (table4);
table3 = NULL;
/* Insert a bunch of stuff then check

View file

@ -29,17 +29,17 @@
DBUS_BEGIN_DECLS;
/* The iterator is on the stack, but its real fields are
* hidden privately.
/** Hash iterator object. The iterator is on the stack, but its real
* fields are hidden privately.
*/
struct DBusHashIter
{
void *dummy1;
void *dummy2;
void *dummy3;
void *dummy4;
int dummy5;
int dummy6;
void *dummy1; /**< Do not use. */
void *dummy2; /**< Do not use. */
void *dummy3; /**< Do not use. */
void *dummy4; /**< Do not use. */
int dummy5; /**< Do not use. */
int dummy6; /**< Do not use. */
};
typedef struct DBusHashTable DBusHashTable;
@ -52,61 +52,68 @@ typedef struct DBusHashIter DBusHashIter;
*/
typedef enum
{
DBUS_HASH_STRING, /**< Hash keys are strings. */
DBUS_HASH_INT, /**< Hash keys are integers. */
DBUS_HASH_POINTER, /**< Hash keys are pointers. */
DBUS_HASH_ULONG /**< Hash keys are unsigned long. */
DBUS_HASH_STRING, /**< Hash keys are strings. */
DBUS_HASH_TWO_STRINGS, /**< Hash key is two strings in one memory block, i.e. foo\\0bar\\0 */
DBUS_HASH_INT, /**< Hash keys are integers. */
DBUS_HASH_POINTER, /**< Hash keys are pointers. */
DBUS_HASH_ULONG /**< Hash keys are unsigned long. */
} DBusHashType;
DBusHashTable* _dbus_hash_table_new (DBusHashType type,
DBusFreeFunction key_free_function,
DBusFreeFunction value_free_function);
void _dbus_hash_table_ref (DBusHashTable *table);
void _dbus_hash_table_unref (DBusHashTable *table);
void _dbus_hash_iter_init (DBusHashTable *table,
DBusHashIter *iter);
dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter);
void _dbus_hash_iter_remove_entry (DBusHashIter *iter);
void* _dbus_hash_iter_get_value (DBusHashIter *iter);
void _dbus_hash_iter_set_value (DBusHashIter *iter,
void *value);
int _dbus_hash_iter_get_int_key (DBusHashIter *iter);
const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter);
unsigned long _dbus_hash_iter_get_ulong_key (DBusHashIter *iter);
dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashIter *iter);
void* _dbus_hash_table_lookup_string (DBusHashTable *table,
const char *key);
void* _dbus_hash_table_lookup_int (DBusHashTable *table,
int key);
void* _dbus_hash_table_lookup_pointer (DBusHashTable *table,
void *key);
void* _dbus_hash_table_lookup_ulong (DBusHashTable *table,
unsigned long key);
dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table,
const char *key);
dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table,
int key);
dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table,
void *key);
dbus_bool_t _dbus_hash_table_remove_ulong (DBusHashTable *table,
unsigned long key);
dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table,
char *key,
void *value);
dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table,
int key,
void *value);
dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table,
void *key,
void *value);
dbus_bool_t _dbus_hash_table_insert_ulong (DBusHashTable *table,
unsigned long key,
void *value);
int _dbus_hash_table_get_n_entries (DBusHashTable *table);
DBusHashTable* _dbus_hash_table_new (DBusHashType type,
DBusFreeFunction key_free_function,
DBusFreeFunction value_free_function);
void _dbus_hash_table_ref (DBusHashTable *table);
void _dbus_hash_table_unref (DBusHashTable *table);
void _dbus_hash_iter_init (DBusHashTable *table,
DBusHashIter *iter);
dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter);
void _dbus_hash_iter_remove_entry (DBusHashIter *iter);
void* _dbus_hash_iter_get_value (DBusHashIter *iter);
void _dbus_hash_iter_set_value (DBusHashIter *iter,
void *value);
int _dbus_hash_iter_get_int_key (DBusHashIter *iter);
const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter);
const char* _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter);
unsigned long _dbus_hash_iter_get_ulong_key (DBusHashIter *iter);
dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,
DBusHashIter *iter);
void* _dbus_hash_table_lookup_string (DBusHashTable *table,
const char *key);
void* _dbus_hash_table_lookup_two_strings (DBusHashTable *table,
const char *key);
void* _dbus_hash_table_lookup_int (DBusHashTable *table,
int key);
void* _dbus_hash_table_lookup_pointer (DBusHashTable *table,
void *key);
void* _dbus_hash_table_lookup_ulong (DBusHashTable *table,
unsigned long key);
dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table,
const char *key);
dbus_bool_t _dbus_hash_table_remove_two_strings (DBusHashTable *table,
const char *key);
dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table,
int key);
dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table,
void *key);
dbus_bool_t _dbus_hash_table_remove_ulong (DBusHashTable *table,
unsigned long key);
dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table,
char *key,
void *value);
dbus_bool_t _dbus_hash_table_insert_two_strings (DBusHashTable *table,
char *key,
void *value);
dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table,
int key,
void *value);
dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table,
void *key,
void *value);
dbus_bool_t _dbus_hash_table_insert_ulong (DBusHashTable *table,
unsigned long key,
void *value);
int _dbus_hash_table_get_n_entries (DBusHashTable *table);
/* Preallocation */
typedef struct DBusPreallocatedHash DBusPreallocatedHash;

View file

@ -248,7 +248,7 @@ _dbus_verbose_reset_real (void)
char*
_dbus_strdup (const char *str)
{
int len;
size_t len;
char *copy;
if (str == NULL)
@ -265,6 +265,29 @@ _dbus_strdup (const char *str)
return copy;
}
/**
* Duplicates a block of memory. Returns
* #NULL on failure.
*
* @param mem memory to copy
* @param n_bytes number of bytes to copy
* @returns the copy
*/
void*
_dbus_memdup (const void *mem,
size_t n_bytes)
{
void *copy;
copy = dbus_malloc (n_bytes);
if (copy == NULL)
return NULL;
memcpy (copy, mem, n_bytes);
return copy;
}
/**
* Duplicates a string array. Result may be freed with
* dbus_free_string_array(). Returns #NULL if memory allocation fails.
@ -366,7 +389,40 @@ _dbus_type_to_string (int type)
}
}
/**
* Returns a string describing the given name.
*
* @param header_field the field to describe
* @returns a constant string describing the field
*/
const char *
_dbus_header_field_to_string (int header_field)
{
switch (header_field)
{
case DBUS_HEADER_FIELD_INVALID:
return "invalid";
case DBUS_HEADER_FIELD_PATH:
return "path";
case DBUS_HEADER_FIELD_INTERFACE:
return "interface";
case DBUS_HEADER_FIELD_MEMBER:
return "member";
case DBUS_HEADER_FIELD_ERROR_NAME:
return "error-name";
case DBUS_HEADER_FIELD_REPLY_SERIAL:
return "reply-serial";
case DBUS_HEADER_FIELD_SERVICE:
return "service";
case DBUS_HEADER_FIELD_SENDER_SERVICE:
return "sender-service";
default:
return "unknown";
}
}
#ifndef DBUS_DISABLE_CHECKS
/** String used in _dbus_return_if_fail macro */
const char _dbus_return_if_fail_warning_format[] =
"Arguments to %s were incorrect, assertion \"%s\" failed in file %s line %d.\n"
"This is normally a bug in some application using the D-BUS library.\n";

View file

@ -144,6 +144,8 @@ extern const char _dbus_return_if_fail_warning_format[];
((void*)_DBUS_ALIGN_VALUE(this, boundary))
char* _dbus_strdup (const char *str);
void* _dbus_memdup (const void *mem,
size_t n_bytes);
dbus_bool_t _dbus_string_array_contains (const char **array,
const char *str);
char** _dbus_dup_string_array (const char **array);
@ -182,7 +184,8 @@ void _dbus_verbose_bytes_of_string (const DBusString *str,
int len);
const char* _dbus_type_to_string (int type);
const char* _dbus_type_to_string (int type);
const char* _dbus_header_field_to_string (int header_field);
extern const char _dbus_no_memory_message[];
#define _DBUS_SET_OOM(error) dbus_set_error ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message)
@ -228,10 +231,10 @@ extern int _dbus_current_generation;
_DBUS_DECLARE_GLOBAL_LOCK (list);
_DBUS_DECLARE_GLOBAL_LOCK (connection_slots);
_DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots);
_DBUS_DECLARE_GLOBAL_LOCK (server_slots);
_DBUS_DECLARE_GLOBAL_LOCK (message_slots);
_DBUS_DECLARE_GLOBAL_LOCK (atomic);
_DBUS_DECLARE_GLOBAL_LOCK (message_handler);
_DBUS_DECLARE_GLOBAL_LOCK (bus);
_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
_DBUS_DECLARE_GLOBAL_LOCK (system_users);

View file

@ -85,6 +85,9 @@
#define MAX_KEYS_IN_FILE 256
#endif
/**
* A single key from the cookie file
*/
typedef struct
{
dbus_int32_t id; /**< identifier used to refer to the key */

View file

@ -23,10 +23,12 @@
#include "dbus-mainloop.h"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <dbus/dbus-list.h>
#include <dbus/dbus-sysdeps.h>
#define MAINLOOP_SPEW 1
#define MAINLOOP_SPEW 0
struct DBusLoop
{
@ -876,3 +878,4 @@ _dbus_wait_for_memory (void)
_dbus_sleep_milliseconds (_dbus_get_oom_wait ());
}
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

View file

@ -24,6 +24,8 @@
#ifndef DBUS_MAINLOOP_H
#define DBUS_MAINLOOP_H
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <dbus/dbus.h>
typedef struct DBusLoop DBusLoop;
@ -68,4 +70,7 @@ dbus_bool_t _dbus_loop_dispatch (DBusLoop *loop);
int _dbus_get_oom_wait (void);
void _dbus_wait_for_memory (void);
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
#endif /* DBUS_MAINLOOP_H */

View file

@ -73,13 +73,17 @@ swap_bytes (unsigned char *data,
}
#endif /* !DBUS_HAVE_INT64 */
/**
* Union used to manipulate 8 bytes as if they
* were various types.
*/
typedef union
{
#ifdef DBUS_HAVE_INT64
dbus_int64_t s;
dbus_uint64_t u;
dbus_int64_t s; /**< 64-bit integer */
dbus_uint64_t u; /**< 64-bit unsinged integer */
#endif
double d;
double d; /**< double */
} DBusOctets8;
static DBusOctets8
@ -98,7 +102,8 @@ unpack_8_octets (int byte_order,
r.u = DBUS_UINT64_FROM_BE (*(dbus_uint64_t*)data);
#else
r.d = *(double*)data;
swap_bytes (&r, sizeof (r));
if (byte_order != DBUS_COMPILER_BYTE_ORDER)
swap_bytes ((unsigned char*) &r, sizeof (r));
#endif
return r;
@ -390,6 +395,10 @@ _dbus_marshal_set_uint64 (DBusString *str,
* an existing string or the wrong length will be deleted
* and replaced with the new string.
*
* Note: no attempt is made by this function to re-align
* any data which has been already marshalled after this
* string. Use with caution.
*
* @param str the string to write the marshalled string to
* @param offset the byte offset where string should be written
* @param byte_order the byte order to use
@ -423,6 +432,30 @@ _dbus_marshal_set_string (DBusString *str,
return TRUE;
}
/**
* Sets the existing marshaled object path at the given offset to a new
* value. The given offset must point to an existing object path or this
* function doesn't make sense.
*
* @todo implement this function
*
* @param str the string to write the marshalled path to
* @param offset the byte offset where path should be written
* @param byte_order the byte order to use
* @param path the new path
* @param path_len number of elements in the path
*/
void
_dbus_marshal_set_object_path (DBusString *str,
int byte_order,
int offset,
const char **path,
int path_len)
{
/* FIXME */
}
static dbus_bool_t
marshal_4_octets (DBusString *str,
int byte_order,
@ -682,7 +715,7 @@ marshal_8_octets_array (DBusString *str,
#ifdef DBUS_HAVE_INT64
*((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d));
#else
swap_bytes (d, 8);
swap_bytes ((unsigned char*) d, 8);
#endif
d += 8;
}
@ -844,6 +877,58 @@ _dbus_marshal_string_array (DBusString *str,
return FALSE;
}
/**
* Marshals an object path value.
*
* @param str the string to append the marshalled value to
* @param byte_order the byte order to use
* @param path the path
* @param path_len length of the path
* @returns #TRUE on success
*/
dbus_bool_t
_dbus_marshal_object_path (DBusString *str,
int byte_order,
const char **path,
int path_len)
{
int array_start, old_string_len;
int i;
old_string_len = _dbus_string_get_length (str);
/* Set the length to 0 temporarily */
if (!_dbus_marshal_uint32 (str, byte_order, 0))
goto nomem;
array_start = _dbus_string_get_length (str);
i = 0;
while (i < path_len)
{
if (!_dbus_string_append_byte (str, '/'))
goto nomem;
if (!_dbus_string_append (str, path[0]))
goto nomem;
++i;
}
/* Write the length now that we know it */
_dbus_marshal_set_uint32 (str, byte_order,
_DBUS_ALIGN_VALUE (old_string_len, sizeof(dbus_uint32_t)),
_dbus_string_get_length (str) - array_start);
return TRUE;
nomem:
/* Restore the previous length */
_dbus_string_set_length (str, old_string_len);
return FALSE;
}
static dbus_uint32_t
demarshal_4_octets (const DBusString *str,
int byte_order,
@ -1174,7 +1259,7 @@ demarshal_8_octets_array (const DBusString *str,
#ifdef DBUS_HAVE_INT64
retval[i].u = DBUS_UINT64_SWAP_LE_BE (retval[i].u);
#else
swap_bytes (&retval[i], 8);
swap_bytes ((unsigned char *) &retval[i], 8);
#endif
}
}
@ -1393,6 +1478,105 @@ _dbus_demarshal_string_array (const DBusString *str,
return FALSE;
}
/** Set to 1 to get a bunch of spew about disassembling the path string */
#define VERBOSE_DECOMPOSE 0
/**
* Demarshals an object path. A path of just "/" is
* represented as an empty vector of strings.
*
* @param str the string containing the data
* @param byte_order the byte order
* @param pos the position in the string
* @param new_pos the new position of the string
* @param path address to store new object path
* @param path_len length of stored path
*/
dbus_bool_t
_dbus_demarshal_object_path (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
char ***path,
int *path_len)
{
int len;
char **retval;
const char *data;
int n_components;
int i, j, comp;
len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
data = _dbus_string_get_const_data_len (str, pos, len + 1);
_dbus_assert (data != NULL);
#if VERBOSE_DECOMPOSE
_dbus_verbose ("Decomposing path \"%s\"\n",
data);
#endif
n_components = 0;
i = 0;
while (i < len)
{
if (data[i] == '/')
n_components += 1;
++i;
}
retval = dbus_new0 (char*, n_components + 1);
if (retval == NULL)
return FALSE;
comp = 0;
i = 0;
while (i < len)
{
if (data[i] == '/')
++i;
j = i;
while (j < len && data[j] != '/')
++j;
/* Now [i, j) is the path component */
_dbus_assert (i < j);
_dbus_assert (data[i] != '/');
_dbus_assert (j == len || data[j] == '/');
#if VERBOSE_DECOMPOSE
_dbus_verbose (" (component in [%d,%d))\n",
i, j);
#endif
retval[comp] = _dbus_memdup (&data[i], j - i + 1);
if (retval[comp] == NULL)
{
dbus_free_string_array (retval);
return FALSE;
}
retval[comp][j-i] = '\0';
#if VERBOSE_DECOMPOSE
_dbus_verbose (" (component %d = \"%s\")\n",
comp, retval[comp]);
#endif
++comp;
i = j;
}
_dbus_assert (i == len);
*path = retval;
if (path_len)
*path_len = n_components;
if (new_pos)
*new_pos = pos + len + 1;
return TRUE;
}
/**
* Returns the position right after the end of an argument. PERFORMS
* NO VALIDATION WHATSOEVER. The message must have been previously
@ -1435,32 +1619,18 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str,
break;
case DBUS_TYPE_INT32:
*end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
break;
case DBUS_TYPE_UINT32:
*end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
*end_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4;
break;
#ifdef DBUS_HAVE_INT64
case DBUS_TYPE_INT64:
*end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int64_t)) + sizeof (dbus_int64_t);
break;
case DBUS_TYPE_UINT64:
*end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint64_t)) + sizeof (dbus_uint64_t);
break;
#endif /* DBUS_HAVE_INT64 */
case DBUS_TYPE_DOUBLE:
*end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (double)) + sizeof (double);
*end_pos = _DBUS_ALIGN_VALUE (pos, 8) + 8;
break;
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_STRING:
{
int len;
@ -1664,6 +1834,7 @@ validate_array_data (const DBusString *str,
case DBUS_TYPE_NIL:
break;
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_STRING:
case DBUS_TYPE_NAMED:
case DBUS_TYPE_ARRAY:
@ -1744,10 +1915,6 @@ validate_array_data (const DBusString *str,
* returns #TRUE if a valid arg begins at "pos"
*
* @todo security: need to audit this function.
*
* @todo For array types that can't be invalid, we should not
* walk the whole array validating it. e.g. just skip all the
* int values in an int array.
*
* @param str a string
* @param byte_order the byte order to use
@ -1842,21 +2009,7 @@ _dbus_marshal_validate_arg (const DBusString *str,
break;
case DBUS_TYPE_INT64:
case DBUS_TYPE_UINT64:
{
int align_8 = _DBUS_ALIGN_VALUE (pos, 8);
if (!_dbus_string_validate_nul (str, pos,
align_8 - pos))
{
_dbus_verbose ("int64/uint64 alignment padding not initialized to nul\n");
return FALSE;
}
*end_pos = align_8 + 8;
}
break;
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
{
int align_8 = _DBUS_ALIGN_VALUE (pos, 8);
@ -1866,7 +2019,7 @@ _dbus_marshal_validate_arg (const DBusString *str,
if (!_dbus_string_validate_nul (str, pos,
align_8 - pos))
{
_dbus_verbose ("double alignment padding not initialized to nul\n");
_dbus_verbose ("double/int64/uint64/objid alignment padding not initialized to nul\n");
return FALSE;
}
@ -1874,6 +2027,7 @@ _dbus_marshal_validate_arg (const DBusString *str,
}
break;
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_STRING:
{
int len;
@ -1887,6 +2041,12 @@ _dbus_marshal_validate_arg (const DBusString *str,
if (!validate_string (str, pos, len, end_pos))
return FALSE;
if (type == DBUS_TYPE_OBJECT_PATH)
{
if (!_dbus_string_validate_path (str, pos, len))
return FALSE;
}
}
break;
@ -2478,7 +2638,6 @@ _dbus_marshal_test (void)
s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL);
_dbus_assert (strcmp (s, "Hello") == 0);
dbus_free (s);
_dbus_string_free (&str);

View file

@ -152,11 +152,17 @@ void _dbus_marshal_set_uint64 (DBusString *str,
int offset,
dbus_uint64_t value);
#endif /* DBUS_HAVE_INT64 */
dbus_bool_t _dbus_marshal_set_string (DBusString *str,
int byte_order,
int offset,
const DBusString *value,
int len);
dbus_bool_t _dbus_marshal_set_string (DBusString *str,
int byte_order,
int offset,
const DBusString *value,
int len);
void _dbus_marshal_set_object_path (DBusString *str,
int byte_order,
int offset,
const char **path,
int path_len);
dbus_bool_t _dbus_marshal_int32 (DBusString *str,
int byte_order,
@ -208,6 +214,11 @@ dbus_bool_t _dbus_marshal_string_array (DBusString *str,
int byte_order,
const char **value,
int len);
dbus_bool_t _dbus_marshal_object_path (DBusString *str,
int byte_order,
const char **path,
int path_len);
double _dbus_demarshal_double (const DBusString *str,
int byte_order,
int pos,
@ -278,9 +289,12 @@ dbus_bool_t _dbus_demarshal_string_array (const DBusString *str,
int *new_pos,
char ***array,
int *array_len);
dbus_bool_t _dbus_demarshal_object_path (const DBusString *str,
int byte_order,
int pos,
int *new_pos,
char ***path,
int *path_len);
dbus_bool_t _dbus_marshal_get_arg_end_pos (const DBusString *str,
int byte_order,

View file

@ -31,11 +31,14 @@ DBUS_BEGIN_DECLS;
typedef struct DBusMD5Context DBusMD5Context;
/**
* A context used to store the state of the MD5 algorithm
*/
struct DBusMD5Context
{
dbus_uint32_t count[2]; /* message length in bits, lsw first */
dbus_uint32_t abcd[4]; /* digest buffer */
unsigned char buf[64]; /* accumulate block */
dbus_uint32_t count[2]; /**< message length in bits, lsw first */
dbus_uint32_t abcd[4]; /**< digest buffer */
unsigned char buf[64]; /**< accumulate block */
};
void _dbus_md5_init (DBusMD5Context *context);

View file

@ -40,9 +40,12 @@
* @{
*/
/**
* Saved length
*/
typedef struct
{
DBusString name;
DBusString name; /**< Name of the length */
int start; /**< Calculate length since here */
int length; /**< length to write */
int offset; /**< where to write it into the data */
@ -265,6 +268,73 @@ append_saved_length (DBusString *dest,
return TRUE;
}
static int
message_type_from_string (const DBusString *str,
int start)
{
const char *s;
s = _dbus_string_get_const_data_len (str, start,
_dbus_string_get_length (str) - start);
if (strncmp (s, "method_call", strlen ("method_call")) == 0)
return DBUS_MESSAGE_TYPE_METHOD_CALL;
else if (strncmp (s, "method_return", strlen ("method_return")) == 0)
return DBUS_MESSAGE_TYPE_METHOD_RETURN;
else if (strncmp (s, "signal", strlen ("signal")) == 0)
return DBUS_MESSAGE_TYPE_SIGNAL;
else if (strncmp (s, "error", strlen ("error")) == 0)
return DBUS_MESSAGE_TYPE_ERROR;
else if (strncmp (s, "invalid", strlen ("invalid")) == 0)
return DBUS_MESSAGE_TYPE_INVALID;
else
return -1;
}
static dbus_bool_t
append_string_field (DBusString *dest,
int endian,
int field,
int type,
const char *value)
{
int len;
if (!_dbus_string_append_byte (dest, field))
{
_dbus_warn ("couldn't append field name byte\n");
return FALSE;
}
if (!_dbus_string_append_byte (dest, type))
{
_dbus_warn ("could not append typecode byte\n");
return FALSE;
}
len = strlen (value);
if (!_dbus_marshal_uint32 (dest, endian, len))
{
_dbus_warn ("couldn't append string length\n");
return FALSE;
}
if (!_dbus_string_append (dest, value))
{
_dbus_warn ("couldn't append field value\n");
return FALSE;
}
if (!_dbus_string_append_byte (dest, 0))
{
_dbus_warn ("couldn't append string nul term\n");
return FALSE;
}
return TRUE;
}
/**
* Reads the given filename, which should be in "message description
* language" (look at some examples), and builds up the message data
@ -274,7 +344,8 @@ append_saved_length (DBusString *dest,
*
* The file format is:
* @code
* VALID_HEADER normal header; byte order, padding, header len, body len, serial
* VALID_HEADER <type> normal header; byte order, type, padding, header len, body len, serial
* REQUIRED_FIELDS add required fields with placeholder values
* BIG_ENDIAN switch to big endian
* LITTLE_ENDIAN switch to little endian
* OPPOSITE_ENDIAN switch to opposite endian
@ -286,7 +357,7 @@ append_saved_length (DBusString *dest,
* (or if no START_LENGTH, absolute length)
* LENGTH <name> inserts the saved length of the same name
* CHOP <N> chops last N bytes off the data
* FIELD_NAME <abcd> inserts 4-byte field name
* HEADER_FIELD <fieldname> inserts a header field name byte
* TYPE <typename> inserts a typecode byte
* @endcode
*
@ -299,6 +370,7 @@ append_saved_length (DBusString *dest,
* UINT64 <N> marshals a UINT64
* DOUBLE <N> marshals a double
* STRING 'Foo' marshals a string
* OBJECT_PATH '/foo/bar' marshals an object path
* BYTE_ARRAY { 'a', 3, 4, 5, 6} marshals a BYTE array
* BOOLEAN_ARRAY { false, true, false} marshals a BOOLEAN array
* INT32_ARRAY { 3, 4, 5, 6} marshals an INT32 array
@ -386,6 +458,13 @@ _dbus_message_data_load (DBusString *dest,
{
int i;
DBusString name;
int message_type;
if (_dbus_string_get_length (&line) < (int) strlen ("VALID_HEADER "))
{
_dbus_warn ("no args to VALID_HEADER\n");
goto parse_failed;
}
if (!_dbus_string_append_byte (dest, endian))
{
@ -393,8 +472,22 @@ _dbus_message_data_load (DBusString *dest,
goto parse_failed;
}
message_type = message_type_from_string (&line,
strlen ("VALID_HEADER "));
if (message_type < 0)
{
_dbus_warn ("VALID_HEADER not followed by space then known message type\n");
goto parse_failed;
}
if (!_dbus_string_append_byte (dest, message_type))
{
_dbus_warn ("could not append message type\n");
goto parse_failed;
}
i = 0;
while (i < 3)
while (i < 2)
{
if (!_dbus_string_append_byte (dest, '\0'))
{
@ -423,6 +516,25 @@ _dbus_message_data_load (DBusString *dest,
goto parse_failed;
}
}
else if (_dbus_string_starts_with_c_str (&line,
"REQUIRED_FIELDS"))
{
if (!append_string_field (dest, endian,
DBUS_HEADER_FIELD_INTERFACE,
DBUS_TYPE_STRING,
"org.freedesktop.BlahBlahInterface"))
goto parse_failed;
if (!append_string_field (dest, endian,
DBUS_HEADER_FIELD_MEMBER,
DBUS_TYPE_STRING,
"BlahBlahMethod"))
goto parse_failed;
if (!append_string_field (dest, endian,
DBUS_HEADER_FIELD_PATH,
DBUS_TYPE_OBJECT_PATH,
"/blah/blah/path"))
goto parse_failed;
}
else if (_dbus_string_starts_with_c_str (&line,
"BIG_ENDIAN"))
{
@ -561,25 +673,42 @@ _dbus_message_data_load (DBusString *dest,
PERFORM_UNALIGN (dest);
}
else if (_dbus_string_starts_with_c_str (&line,
"FIELD_NAME"))
"HEADER_FIELD"))
{
int field;
_dbus_string_delete_first_word (&line);
if (_dbus_string_get_length (&line) != 4)
if (_dbus_string_starts_with_c_str (&line, "INVALID"))
field = DBUS_HEADER_FIELD_INVALID;
else if (_dbus_string_starts_with_c_str (&line, "PATH"))
field = DBUS_HEADER_FIELD_PATH;
else if (_dbus_string_starts_with_c_str (&line, "INTERFACE"))
field = DBUS_HEADER_FIELD_INTERFACE;
else if (_dbus_string_starts_with_c_str (&line, "MEMBER"))
field = DBUS_HEADER_FIELD_MEMBER;
else if (_dbus_string_starts_with_c_str (&line, "ERROR_NAME"))
field = DBUS_HEADER_FIELD_ERROR_NAME;
else if (_dbus_string_starts_with_c_str (&line, "REPLY_SERIAL"))
field = DBUS_HEADER_FIELD_REPLY_SERIAL;
else if (_dbus_string_starts_with_c_str (&line, "SERVICE"))
field = DBUS_HEADER_FIELD_SERVICE;
else if (_dbus_string_starts_with_c_str (&line, "SENDER_SERVICE"))
field = DBUS_HEADER_FIELD_SENDER_SERVICE;
else if (_dbus_string_starts_with_c_str (&line, "UNKNOWN"))
field = 22; /* random unknown header field */
else
{
_dbus_warn ("Field name must be four characters not \"%s\"\n",
_dbus_string_get_const_data (&line));
_dbus_warn ("%s is not a valid header field name\n",
_dbus_string_get_const_data (&line));
goto parse_failed;
}
if (unalign)
unalign = FALSE;
else
_dbus_string_align_length (dest, 4);
if (!_dbus_string_copy (&line, 0, dest,
_dbus_string_get_length (dest)))
goto parse_failed;
if (!_dbus_string_append_byte (dest, field))
{
_dbus_warn ("could not append header field name byte\n");
goto parse_failed;
}
}
else if (_dbus_string_starts_with_c_str (&line,
"TYPE"))
@ -604,6 +733,8 @@ _dbus_message_data_load (DBusString *dest,
code = DBUS_TYPE_DOUBLE;
else if (_dbus_string_starts_with_c_str (&line, "STRING"))
code = DBUS_TYPE_STRING;
else if (_dbus_string_starts_with_c_str (&line, "OBJECT_PATH"))
code = DBUS_TYPE_OBJECT_PATH;
else if (_dbus_string_starts_with_c_str (&line, "NAMED"))
code = DBUS_TYPE_NAMED;
else if (_dbus_string_starts_with_c_str (&line, "ARRAY"))
@ -1226,6 +1357,36 @@ _dbus_message_data_load (DBusString *dest,
PERFORM_UNALIGN (dest);
}
else if (_dbus_string_starts_with_c_str (&line,
"OBJECT_PATH"))
{
SAVE_FOR_UNALIGN (dest, 4);
int size_offset;
int old_len;
_dbus_string_delete_first_word (&line);
size_offset = _dbus_string_get_length (dest);
size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
if (!_dbus_marshal_uint32 (dest, endian, 0))
{
_dbus_warn ("Failed to append string size\n");
goto parse_failed;
}
old_len = _dbus_string_get_length (dest);
if (!append_quoted_string (dest, &line, 0, NULL))
{
_dbus_warn ("Failed to append quoted string\n");
goto parse_failed;
}
_dbus_marshal_set_uint32 (dest, endian, size_offset,
/* subtract 1 for nul */
_dbus_string_get_length (dest) - old_len - 1);
PERFORM_UNALIGN (dest);
}
else
goto parse_failed;

File diff suppressed because it is too large Load diff

View file

@ -31,6 +31,7 @@
#include <dbus/dbus-types.h>
#include <dbus/dbus-arch-deps.h>
#include <dbus/dbus-memory.h>
#include <dbus/dbus-errors.h>
#include <stdarg.h>
DBUS_BEGIN_DECLS;
@ -38,45 +39,74 @@ DBUS_BEGIN_DECLS;
typedef struct DBusMessage DBusMessage;
typedef struct DBusMessageIter DBusMessageIter;
/**
* DBusMessageIter struct; contains no public fields
*/
struct DBusMessageIter
{
void *dummy1;
void *dummy2;
dbus_uint32_t dummy3;
int dummy4;
int dummy5;
int dummy6;
int dummy7;
int dummy8;
int dummy9;
int dummy10;
int dummy11;
int pad1;
int pad2;
void *pad3;
{
void *dummy1; /**< Don't use this */
void *dummy2; /**< Don't use this */
dbus_uint32_t dummy3; /**< Don't use this */
int dummy4; /**< Don't use this */
int dummy5; /**< Don't use this */
int dummy6; /**< Don't use this */
int dummy7; /**< Don't use this */
int dummy8; /**< Don't use this */
int dummy9; /**< Don't use this */
int dummy10; /**< Don't use this */
int dummy11; /**< Don't use this */
int pad1; /**< Don't use this */
int pad2; /**< Don't use this */
void *pad3; /**< Don't use this */
};
DBusMessage* dbus_message_new (int message_type);
DBusMessage* dbus_message_new_method_call (const char *service,
const char *path,
const char *interface,
const char *method);
DBusMessage* dbus_message_new_method_return (DBusMessage *method_call);
DBusMessage* dbus_message_new_signal (const char *path,
const char *interface,
const char *name);
DBusMessage* dbus_message_new_error (DBusMessage *reply_to,
const char *error_name,
const char *error_message);
DBusMessage* dbus_message_new (const char *name,
const char *destination_service);
DBusMessage* dbus_message_new_reply (DBusMessage *original_message);
DBusMessage* dbus_message_new_error_reply (DBusMessage *original_message,
const char *error_name,
const char *error_message);
DBusMessage *dbus_message_copy (const DBusMessage *message);
DBusMessage *dbus_message_copy (const DBusMessage *message);
void dbus_message_ref (DBusMessage *message);
void dbus_message_unref (DBusMessage *message);
const char* dbus_message_get_name (DBusMessage *message);
int dbus_message_get_type (DBusMessage *message);
dbus_bool_t dbus_message_set_path (DBusMessage *message,
const char *object_path);
const char* dbus_message_get_path (DBusMessage *message);
dbus_bool_t dbus_message_set_interface (DBusMessage *message,
const char *interface);
const char* dbus_message_get_interface (DBusMessage *message);
dbus_bool_t dbus_message_set_member (DBusMessage *message,
const char *member);
const char* dbus_message_get_member (DBusMessage *message);
dbus_bool_t dbus_message_set_error_name (DBusMessage *message,
const char *name);
const char* dbus_message_get_error_name (DBusMessage *message);
dbus_bool_t dbus_message_set_destination (DBusMessage *message,
const char *destination);
const char* dbus_message_get_destination (DBusMessage *message);
dbus_bool_t dbus_message_set_sender (DBusMessage *message,
const char *sender);
const char* dbus_message_get_sender (DBusMessage *message);
void dbus_message_set_is_error (DBusMessage *message,
dbus_bool_t is_error_reply);
dbus_bool_t dbus_message_get_is_error (DBusMessage *message);
dbus_bool_t dbus_message_has_name (DBusMessage *message,
const char *name);
void dbus_message_set_no_reply (DBusMessage *message,
dbus_bool_t no_reply);
dbus_bool_t dbus_message_get_no_reply (DBusMessage *message);
dbus_bool_t dbus_message_is_method_call (DBusMessage *message,
const char *interface,
const char *method);
dbus_bool_t dbus_message_is_signal (DBusMessage *message,
const char *interface,
const char *signal_name);
dbus_bool_t dbus_message_is_error (DBusMessage *message,
const char *error_name);
dbus_bool_t dbus_message_has_destination (DBusMessage *message,
const char *service);
dbus_bool_t dbus_message_has_sender (DBusMessage *message,
@ -86,6 +116,9 @@ dbus_bool_t dbus_message_set_reply_serial (DBusMessage *message,
dbus_uint32_t reply_serial);
dbus_uint32_t dbus_message_get_reply_serial (DBusMessage *message);
dbus_bool_t dbus_message_get_path_decomposed (DBusMessage *message,
char ***path);
dbus_bool_t dbus_message_append_args (DBusMessage *message,
int first_arg_type,
...);

1481
dbus/dbus-object-tree.c Normal file

File diff suppressed because it is too large Load diff

52
dbus/dbus-object-tree.h Normal file
View file

@ -0,0 +1,52 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-object-tree.h DBusObjectTree (internals of DBusConnection)
*
* Copyright (C) 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_OBJECT_TREE_H
#define DBUS_OBJECT_TREE_H
#include <dbus/dbus-connection.h>
DBUS_BEGIN_DECLS;
typedef struct DBusObjectTree DBusObjectTree;
DBusObjectTree* _dbus_object_tree_new (DBusConnection *connection);
void _dbus_object_tree_ref (DBusObjectTree *tree);
void _dbus_object_tree_unref (DBusObjectTree *tree);
dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree,
dbus_bool_t fallback,
const char **path,
const DBusObjectPathVTable *vtable,
void *user_data);
void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree,
const char **path);
DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
DBusMessage *message);
void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree);
dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
const char **parent_path,
char ***child_entries);
DBUS_END_DECLS;
#endif /* DBUS_OBJECT_TREE_H */

429
dbus/dbus-pending-call.c Normal file
View file

@ -0,0 +1,429 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-pending-call.c Object representing a call in progress.
*
* Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-internals.h"
#include "dbus-connection-internal.h"
#include "dbus-pending-call.h"
#include "dbus-list.h"
#include "dbus-threads.h"
#include "dbus-test.h"
/**
* @defgroup DBusPendingCallInternals DBusPendingCall implementation details
* @ingroup DBusInternals
* @brief DBusPendingCall private implementation details.
*
* The guts of DBusPendingCall and its methods.
*
* @{
*/
static dbus_int32_t notify_user_data_slot = -1;
/**
* Creates a new pending reply object.
*
* @param connection connection where reply will arrive
* @param timeout_milliseconds length of timeout, -1 for default
* @param timeout_handler timeout handler, takes pending call as data
* @returns a new #DBusPendingCall or #NULL if no memory.
*/
DBusPendingCall*
_dbus_pending_call_new (DBusConnection *connection,
int timeout_milliseconds,
DBusTimeoutHandler timeout_handler)
{
DBusPendingCall *pending;
DBusTimeout *timeout;
_dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
if (timeout_milliseconds == -1)
timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
if (!dbus_pending_call_allocate_data_slot (&notify_user_data_slot))
return NULL;
pending = dbus_new (DBusPendingCall, 1);
if (pending == NULL)
{
dbus_pending_call_free_data_slot (&notify_user_data_slot);
return NULL;
}
timeout = _dbus_timeout_new (timeout_milliseconds,
timeout_handler,
pending, NULL);
if (timeout == NULL)
{
dbus_pending_call_free_data_slot (&notify_user_data_slot);
dbus_free (pending);
return NULL;
}
pending->refcount.value = 1;
pending->connection = connection;
pending->timeout = timeout;
_dbus_data_slot_list_init (&pending->slot_list);
return pending;
}
/**
* Calls notifier function for the pending call
* and sets the call to completed.
*
* @param pending the pending call
*
*/
void
_dbus_pending_call_notify (DBusPendingCall *pending)
{
pending->completed = TRUE;
if (pending->function)
{
void *user_data;
user_data = dbus_pending_call_get_data (pending,
notify_user_data_slot);
(* pending->function) (pending, user_data);
}
}
/** @} */
/**
* @defgroup DBusPendingCall DBusPendingCall
* @ingroup DBus
* @brief Pending reply to a method call message
*
* A DBusPendingCall is an object representing an
* expected reply. A #DBusPendingCall can be created
* when you send a message that should have a reply.
*
* @{
*/
/**
* @typedef DBusPendingCall
*
* Opaque data type representing a message pending.
*/
/**
* Increments the reference count on a pending call.
*
* @param pending the pending call object
*/
void
dbus_pending_call_ref (DBusPendingCall *pending)
{
_dbus_return_if_fail (pending != NULL);
_dbus_atomic_inc (&pending->refcount);
}
/**
* Decrements the reference count on a pending call,
* freeing it if the count reaches 0.
*
* @param pending the pending call object
*/
void
dbus_pending_call_unref (DBusPendingCall *pending)
{
dbus_bool_t last_unref;
_dbus_return_if_fail (pending != NULL);
last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
if (last_unref)
{
/* If we get here, we should be already detached
* from the connection, or never attached.
*/
_dbus_assert (pending->connection == NULL);
_dbus_assert (!pending->timeout_added);
/* this assumes we aren't holding connection lock... */
_dbus_data_slot_list_free (&pending->slot_list);
if (pending->timeout != NULL)
_dbus_timeout_unref (pending->timeout);
if (pending->timeout_link)
{
dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
_dbus_list_free_link (pending->timeout_link);
pending->timeout_link = NULL;
}
if (pending->reply)
{
dbus_message_unref (pending->reply);
pending->reply = NULL;
}
dbus_free (pending);
dbus_pending_call_free_data_slot (&notify_user_data_slot);
}
}
/**
* Sets a notification function to be called when the reply is
* received or the pending call times out.
*
* @param pending the pending call
* @param function notifier function
* @param user_data data to pass to notifier function
* @param free_user_data function to free the user data
* @returns #FALSE if not enough memory
*/
dbus_bool_t
dbus_pending_call_set_notify (DBusPendingCall *pending,
DBusPendingCallNotifyFunction function,
void *user_data,
DBusFreeFunction free_user_data)
{
_dbus_return_val_if_fail (pending != NULL, FALSE);
/* could invoke application code! */
if (!dbus_pending_call_set_data (pending, notify_user_data_slot,
user_data, free_user_data))
return FALSE;
pending->function = function;
return TRUE;
}
/**
* Cancels the pending call, such that any reply
* or error received will just be ignored.
* Drops at least one reference to the #DBusPendingCall
* so will free the call if nobody else is holding
* a reference.
*
* @param pending the pending call
*/
void
dbus_pending_call_cancel (DBusPendingCall *pending)
{
if (pending->connection)
_dbus_connection_remove_pending_call (pending->connection,
pending);
}
/**
* Checks whether the pending call has received a reply
* yet, or not.
*
* @todo not thread safe? I guess it has to lock though it sucks
*
* @param pending the pending call
* @returns #TRUE if a reply has been received */
dbus_bool_t
dbus_pending_call_get_completed (DBusPendingCall *pending)
{
return pending->completed;
}
/**
* Gets the reply, or returns #NULL if none has been received yet. The
* reference count is not incremented on the returned message, so you
* have to keep a reference count on the pending call (or add one
* to the message).
*
* @todo not thread safe? I guess it has to lock though it sucks
* @todo maybe to make this threadsafe, it should be steal_reply(), i.e. only one thread can ever get the message
*
* @param pending the pending call
* @returns the reply message or #NULL.
*/
DBusMessage*
dbus_pending_call_get_reply (DBusPendingCall *pending)
{
return pending->reply;
}
/**
* Block until the pending call is completed. The blocking is as with
* dbus_connection_send_with_reply_and_block(); it does not enter the
* main loop or process other messages, it simply waits for the reply
* in question.
*
* If the pending call is already completed, this function returns
* immediately.
*
* @todo when you start blocking, the timeout is reset, but it should
* really only use time remaining since the pending call was created.
*
* @param pending the pending call
*/
void
dbus_pending_call_block (DBusPendingCall *pending)
{
DBusMessage *message;
if (dbus_pending_call_get_completed (pending))
return;
message = _dbus_connection_block_for_reply (pending->connection,
pending->reply_serial,
dbus_timeout_get_interval (pending->timeout));
_dbus_connection_lock (pending->connection);
_dbus_pending_call_complete_and_unlock (pending, message);
dbus_message_unref (message);
}
static DBusDataSlotAllocator slot_allocator;
_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
/**
* Allocates an integer ID to be used for storing application-specific
* data on any DBusPendingCall. The allocated ID may then be used
* with dbus_pending_call_set_data() and dbus_pending_call_get_data().
* The passed-in slot must be initialized to -1, and is filled in
* with the slot ID. If the passed-in slot is not -1, it's assumed
* to be already allocated, and its refcount is incremented.
*
* The allocated slot is global, i.e. all DBusPendingCall objects will
* have a slot with the given integer ID reserved.
*
* @param slot_p address of a global variable storing the slot
* @returns #FALSE on failure (no memory)
*/
dbus_bool_t
dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
{
return _dbus_data_slot_allocator_alloc (&slot_allocator,
_DBUS_LOCK_NAME (pending_call_slots),
slot_p);
}
/**
* Deallocates a global ID for #DBusPendingCall data slots.
* dbus_pending_call_get_data() and dbus_pending_call_set_data() may
* no longer be used with this slot. Existing data stored on existing
* DBusPendingCall objects will be freed when the #DBusPendingCall is
* finalized, but may not be retrieved (and may only be replaced if
* someone else reallocates the slot). When the refcount on the
* passed-in slot reaches 0, it is set to -1.
*
* @param slot_p address storing the slot to deallocate
*/
void
dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
{
_dbus_return_if_fail (*slot_p >= 0);
_dbus_data_slot_allocator_free (&slot_allocator, slot_p);
}
/**
* Stores a pointer on a #DBusPendingCall, along
* with an optional function to be used for freeing
* the data when the data is set again, or when
* the pending call is finalized. The slot number
* must have been allocated with dbus_pending_call_allocate_data_slot().
*
* @param pending the pending_call
* @param slot the slot number
* @param data the data to store
* @param free_data_func finalizer function for the data
* @returns #TRUE if there was enough memory to store the data
*/
dbus_bool_t
dbus_pending_call_set_data (DBusPendingCall *pending,
dbus_int32_t slot,
void *data,
DBusFreeFunction free_data_func)
{
DBusFreeFunction old_free_func;
void *old_data;
dbus_bool_t retval;
_dbus_return_val_if_fail (pending != NULL, FALSE);
_dbus_return_val_if_fail (slot >= 0, FALSE);
retval = _dbus_data_slot_list_set (&slot_allocator,
&pending->slot_list,
slot, data, free_data_func,
&old_free_func, &old_data);
if (retval)
{
if (old_free_func)
(* old_free_func) (old_data);
}
return retval;
}
/**
* Retrieves data previously set with dbus_pending_call_set_data().
* The slot must still be allocated (must not have been freed).
*
* @param pending the pending_call
* @param slot the slot to get data from
* @returns the data, or #NULL if not found
*/
void*
dbus_pending_call_get_data (DBusPendingCall *pending,
dbus_int32_t slot)
{
void *res;
_dbus_return_val_if_fail (pending != NULL, NULL);
res = _dbus_data_slot_list_get (&slot_allocator,
&pending->slot_list,
slot);
return res;
}
/** @} */
#ifdef DBUS_BUILD_TESTS
/**
* @ingroup DBusPendingCallInternals
* Unit test for DBusPendingCall.
*
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_pending_call_test (const char *test_data_dir)
{
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */

58
dbus/dbus-pending-call.h Normal file
View file

@ -0,0 +1,58 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-pending-call.h Object representing a call in progress.
*
* Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION)
#error "Only <dbus/dbus.h> can be included directly, this file may disappear or change contents."
#endif
#ifndef DBUS_PENDING_CALL_H
#define DBUS_PENDING_CALL_H
#include <dbus/dbus-macros.h>
#include <dbus/dbus-types.h>
#include <dbus/dbus-connection.h>
DBUS_BEGIN_DECLS;
void dbus_pending_call_ref (DBusPendingCall *pending);
void dbus_pending_call_unref (DBusPendingCall *pending);
dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending,
DBusPendingCallNotifyFunction function,
void *user_data,
DBusFreeFunction free_user_data);
void dbus_pending_call_cancel (DBusPendingCall *pending);
dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending);
DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending);
void dbus_pending_call_block (DBusPendingCall *pending);
dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p);
void dbus_pending_call_free_data_slot (dbus_int32_t *slot_p);
dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending,
dbus_int32_t slot,
void *data,
DBusFreeFunction free_data_func);
void* dbus_pending_call_get_data (DBusPendingCall *pending,
dbus_int32_t slot);
DBUS_END_DECLS;
#endif /* DBUS_PENDING_CALL_H */

View file

@ -53,25 +53,54 @@ extern "C" {
#define DBUS_TYPE_NAMED 10
#define DBUS_TYPE_ARRAY 11
#define DBUS_TYPE_DICT 12
#define DBUS_TYPE_OBJECT_PATH 13
#define DBUS_TYPE_LAST DBUS_TYPE_OBJECT_PATH
#define DBUS_TYPE_LAST DBUS_TYPE_DICT
/* Max length in bytes of a service or message name */
/* Max length in bytes of a service or interface or member name */
#define DBUS_MAXIMUM_NAME_LENGTH 256
/* Types of message */
#define DBUS_MESSAGE_TYPE_INVALID 0
#define DBUS_MESSAGE_TYPE_METHOD_CALL 1
#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2
#define DBUS_MESSAGE_TYPE_ERROR 3
#define DBUS_MESSAGE_TYPE_SIGNAL 4
/* Header flags */
#define DBUS_HEADER_FLAG_ERROR 0x1
#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1
/* Header fields */
#define DBUS_HEADER_FIELD_NAME "name"
#define DBUS_HEADER_FIELD_SERVICE "srvc"
#define DBUS_HEADER_FIELD_REPLY "rply"
#define DBUS_HEADER_FIELD_SENDER "sndr"
#define DBUS_HEADER_FIELD_INVALID 0
#define DBUS_HEADER_FIELD_PATH 1
#define DBUS_HEADER_FIELD_INTERFACE 2
#define DBUS_HEADER_FIELD_MEMBER 3
#define DBUS_HEADER_FIELD_ERROR_NAME 4
#define DBUS_HEADER_FIELD_REPLY_SERIAL 5
#define DBUS_HEADER_FIELD_SERVICE 6
#define DBUS_HEADER_FIELD_SENDER_SERVICE 7
#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_SENDER_SERVICE
/* Services */
#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
#define DBUS_SERVICE_BROADCAST "org.freedesktop.DBus.Broadcast"
#define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus"
/* Paths */
#define DBUS_PATH_ORG_FREEDESKTOP_DBUS "/org/freedesktop/DBus"
#define DBUS_PATH_ORG_FREEDESKTOP_LOCAL "/org/freedesktop/Local"
/* Interfaces, these #define don't do much other than
* catch typos at compile time
*/
#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus"
#define DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE "org.freedesktop.Introspectable"
/* This is a special interface whose methods can only be invoked
* by the local implementation (messages from remote apps aren't
* allowed to specify this interface).
*/
#define DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL "org.freedesktop.Local"
/* Service owner flags */
#define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1
#define DBUS_SERVICE_FLAG_REPLACE_EXISTING 0x2
@ -86,24 +115,6 @@ extern "C" {
#define DBUS_ACTIVATION_REPLY_ACTIVATED 0x0
#define DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE 0x1
/* Messages */
#define DBUS_MESSAGE_ACTIVATE_SERVICE "org.freedesktop.DBus.ActivateService"
#define DBUS_MESSAGE_SERVICE_EXISTS "org.freedesktop.DBus.ServiceExists"
#define DBUS_MESSAGE_HELLO "org.freedesktop.DBus.Hello"
#define DBUS_MESSAGE_LIST_SERVICES "org.freedesktop.DBus.ListServices"
#define DBUS_MESSAGE_ACQUIRE_SERVICE "org.freedesktop.DBus.AcquireService"
#define DBUS_MESSAGE_SERVICE_ACQUIRED "org.freedesktop.DBus.ServiceAcquired"
#define DBUS_MESSAGE_SERVICE_CREATED "org.freedesktop.DBus.ServiceCreated"
#define DBUS_MESSAGE_SERVICE_DELETED "org.freedesktop.DBus.ServiceDeleted"
#define DBUS_MESSAGE_SERVICE_LOST "org.freedesktop.DBus.ServiceLost"
/* This namespace is reserved for locally-synthesized messages, you can't
* send messages that have this namespace.
*/
#define DBUS_NAMESPACE_LOCAL_MESSAGE "org.freedesktop.Local."
#define DBUS_MESSAGE_LOCAL_DISCONNECT DBUS_NAMESPACE_LOCAL_MESSAGE"Disconnect"
#ifdef __cplusplus
}
#endif

View file

@ -27,6 +27,7 @@
#include "dbus-transport-unix.h"
#include "dbus-connection-internal.h"
#include "dbus-hash.h"
#include "dbus-string.h"
#ifdef DBUS_BUILD_TESTS

View file

@ -34,6 +34,9 @@ DBUS_BEGIN_DECLS;
typedef struct DBusServerVTable DBusServerVTable;
/**
* Virtual table to be implemented by all server "subclasses"
*/
struct DBusServerVTable
{
void (* finalize) (DBusServer *server);
@ -43,6 +46,9 @@ struct DBusServerVTable
/**< Disconnect this server. */
};
/**
* Internals of DBusServer object
*/
struct DBusServer
{
int refcount; /**< Reference count. */

View file

@ -25,6 +25,7 @@
#include "dbus-server-unix.h"
#include "dbus-transport-unix.h"
#include "dbus-connection-internal.h"
#include "dbus-string.h"
#include <sys/types.h>
#include <unistd.h>

View file

@ -23,6 +23,7 @@
#include "dbus-server.h"
#include "dbus-server-unix.h"
#include "dbus-string.h"
#ifdef DBUS_BUILD_TESTS
#include "dbus-server-debug-pipe.h"
#endif

View file

@ -31,11 +31,14 @@ DBUS_BEGIN_DECLS;
typedef struct DBusSHAContext DBusSHAContext;
/**
* Struct storing state of the SHA algorithm
*/
struct DBusSHAContext
{
dbus_uint32_t digest[5]; /**< Message digest */
dbus_uint32_t count_lo; /**< 64-bit bit count */
dbus_uint32_t count_hi;
dbus_uint32_t count_hi; /**< No clue */
dbus_uint32_t data[16]; /**< SHA data buffer */
};

View file

@ -176,28 +176,31 @@ enum
CHILD_PID /* Followed by pid_t */
};
/**
* Babysitter implementation details
*/
struct DBusBabysitter
{
int refcount;
int refcount; /**< Reference count */
char *executable; /**< executable name to use in error messages */
int socket_to_babysitter;
int error_pipe_from_child;
int socket_to_babysitter; /**< Connection to the babysitter process */
int error_pipe_from_child; /**< Connection to the process that does the exec() */
pid_t sitter_pid;
pid_t grandchild_pid;
pid_t sitter_pid; /**< PID Of the babysitter */
pid_t grandchild_pid; /**< PID of the grandchild */
DBusWatchList *watches;
DBusWatchList *watches; /**< Watches */
DBusWatch *error_watch;
DBusWatch *sitter_watch;
DBusWatch *error_watch; /**< Error pipe watch */
DBusWatch *sitter_watch; /**< Sitter pipe watch */
int errnum;
int status;
unsigned int have_child_status : 1;
unsigned int have_fork_errnum : 1;
unsigned int have_exec_errnum : 1;
int errnum; /**< Error number */
int status; /**< Exit status code */
unsigned int have_child_status : 1; /**< True if child status has been reaped */
unsigned int have_fork_errnum : 1; /**< True if we have an error code from fork() */
unsigned int have_exec_errnum : 1; /**< True if we have an error code from exec() */
};
static DBusBabysitter*

View file

@ -25,6 +25,8 @@
#include "dbus-string.h"
/* we allow a system header here, for speed/convenience */
#include <string.h>
/* for vsnprintf */
#include <stdio.h>
#include "dbus-marshal.h"
#define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
#include "dbus-string-private.h"
@ -560,26 +562,30 @@ _dbus_string_get_byte (const DBusString *str,
}
/**
* Inserts the given byte at the given position.
* Inserts a number of bytes of a given value at the
* given position.
*
* @param str the string
* @param i the position
* @param n_bytes number of bytes
* @param byte the value to insert
* @returns #TRUE on success
*/
dbus_bool_t
_dbus_string_insert_byte (DBusString *str,
int i,
unsigned char byte)
_dbus_string_insert_bytes (DBusString *str,
int i,
int n_bytes,
unsigned char byte)
{
DBUS_STRING_PREAMBLE (str);
_dbus_assert (i <= real->len);
_dbus_assert (i >= 0);
_dbus_assert (n_bytes > 0);
if (!open_gap (1, real, i))
if (!open_gap (n_bytes, real, i))
return FALSE;
real->str[i] = byte;
memset (real->str + i, byte, n_bytes);
return TRUE;
}
@ -964,7 +970,7 @@ _dbus_string_append_8_aligned (DBusString *str,
p = (dbus_uint64_t*) (real->str + (real->len - 8));
*p = *((dbus_uint64_t*)octets);
#else
char *p;
unsigned char *p;
DBUS_STRING_PREAMBLE (str);
if (!align_length_then_lengthen (str, 8, 8))
@ -986,6 +992,59 @@ _dbus_string_append_8_aligned (DBusString *str,
return TRUE;
}
/**
* Appends a printf-style formatted string
* to the #DBusString.
*
* @param str the string
* @param format printf format
* @param args variable argument list
* @returns #FALSE if no memory
*/
dbus_bool_t
_dbus_string_append_printf_valist (DBusString *str,
const char *format,
va_list args)
{
int len;
char c;
DBUS_STRING_PREAMBLE (str);
/* Measure the message length without terminating nul */
len = vsnprintf (&c, 1, format, args);
if (!_dbus_string_lengthen (str, len))
return FALSE;
vsprintf (real->str + (real->len - len),
format, args);
return TRUE;
}
/**
* Appends a printf-style formatted string
* to the #DBusString.
*
* @param str the string
* @param format printf format
* @returns #FALSE if no memory
*/
dbus_bool_t
_dbus_string_append_printf (DBusString *str,
const char *format,
...)
{
va_list args;
dbus_bool_t retval;
va_start (args, format);
retval = _dbus_string_append_printf_valist (str, format, args);
va_end (args);
return retval;
}
/**
* Appends block of bytes with the given length to a DBusString.
*
@ -1752,7 +1811,7 @@ _dbus_string_skip_white (const DBusString *str,
}
/**
* Assigns a newline-terminated or \r\n-terminated line from the front
* Assigns a newline-terminated or \\r\\n-terminated line from the front
* of the string to the given dest string. The dest string's previous
* contents are deleted. If the source string contains no newline,
* moves the entire source string to the dest string.
@ -2791,13 +2850,16 @@ _dbus_string_validate_nul (const DBusString *str,
}
/**
* Checks that the given range of the string is a valid message name
* in the D-BUS protocol. This includes a length restriction, etc.,
* see the specification. It does not validate UTF-8, that has to be
* done separately for now.
* Checks that the given range of the string is a valid object path
* name in the D-BUS protocol. This includes a length restriction,
* etc., see the specification. It does not validate UTF-8, that has
* to be done separately for now.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
*
* @todo change spec to disallow more things, such as spaces in the
* path name
*
* @param str the string
* @param start first byte index to check
@ -2805,9 +2867,77 @@ _dbus_string_validate_nul (const DBusString *str,
* @returns #TRUE if the byte range exists and is a valid name
*/
dbus_bool_t
_dbus_string_validate_name (const DBusString *str,
_dbus_string_validate_path (const DBusString *str,
int start,
int len)
{
const unsigned char *s;
const unsigned char *end;
const unsigned char *last_slash;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start >= 0);
_dbus_assert (len >= 0);
_dbus_assert (start <= real->len);
if (len > real->len - start)
return FALSE;
if (len > DBUS_MAXIMUM_NAME_LENGTH)
return FALSE;
if (len == 0)
return FALSE;
s = real->str + start;
end = s + len;
if (*s != '/')
return FALSE;
last_slash = s;
++s;
while (s != end)
{
if (*s == '/')
{
if ((s - last_slash) < 2)
return FALSE; /* no empty path components allowed */
last_slash = s;
}
++s;
}
if ((end - last_slash) < 2 &&
len > 1)
return FALSE; /* trailing slash not allowed unless the string is "/" */
return TRUE;
}
/**
* Checks that the given range of the string is a valid interface name
* in the D-BUS protocol. This includes a length restriction, etc.,
* see the specification. It does not validate UTF-8, that has to be
* done separately for now.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
*
* @todo change spec to disallow more things, such as spaces in the
* interface name
*
* @param str the string
* @param start first byte index to check
* @param len number of bytes to check
* @returns #TRUE if the byte range exists and is a valid name
*/
dbus_bool_t
_dbus_string_validate_interface (const DBusString *str,
int start,
int len)
{
const unsigned char *s;
const unsigned char *end;
@ -2847,6 +2977,89 @@ _dbus_string_validate_name (const DBusString *str,
return TRUE;
}
/**
* Checks that the given range of the string is a valid member name
* in the D-BUS protocol. This includes a length restriction, etc.,
* see the specification. It does not validate UTF-8, that has to be
* done separately for now.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
*
* @todo change spec to disallow more things, such as spaces in the
* member name
*
* @param str the string
* @param start first byte index to check
* @param len number of bytes to check
* @returns #TRUE if the byte range exists and is a valid name
*/
dbus_bool_t
_dbus_string_validate_member (const DBusString *str,
int start,
int len)
{
const unsigned char *s;
const unsigned char *end;
dbus_bool_t saw_dot;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start >= 0);
_dbus_assert (len >= 0);
_dbus_assert (start <= real->len);
if (len > real->len - start)
return FALSE;
if (len > DBUS_MAXIMUM_NAME_LENGTH)
return FALSE;
if (len == 0)
return FALSE;
saw_dot = FALSE;
s = real->str + start;
end = s + len;
while (s != end)
{
if (*s == '.')
{
saw_dot = TRUE;
break;
}
++s;
}
/* No dot allowed in member names */
if (saw_dot)
return FALSE;
return TRUE;
}
/**
* Checks that the given range of the string is a valid error name
* in the D-BUS protocol. This includes a length restriction, etc.,
* see the specification. It does not validate UTF-8, that has to be
* done separately for now.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
*
* @param str the string
* @param start first byte index to check
* @param len number of bytes to check
* @returns #TRUE if the byte range exists and is a valid name
*/
dbus_bool_t
_dbus_string_validate_error_name (const DBusString *str,
int start,
int len)
{
/* Same restrictions as interface name at the moment */
return _dbus_string_validate_interface (str, start, len);
}
/**
* Checks that the given range of the string is a valid service name
@ -2856,6 +3069,9 @@ _dbus_string_validate_name (const DBusString *str,
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
*
* @todo change spec to disallow more things, such as spaces in the
* service name
*
* @param str the string
* @param start first byte index to check
@ -3107,6 +3323,24 @@ _dbus_string_test (void)
int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };
char *s;
dbus_unichar_t ch;
const char *valid_paths[] = {
"/",
"/foo/bar",
"/foo",
"/foo/bar/baz"
};
const char *invalid_paths[] = {
"bar",
"bar/baz",
"/foo/bar/",
"/foo/"
"foo/",
"boo//blah",
"//",
"///",
"foo///blah/",
"Hello World"
};
i = 0;
while (i < _DBUS_N_ELEMENTS (lens))
@ -3342,23 +3576,26 @@ _dbus_string_test (void)
_dbus_string_set_byte (&str, 1, 'q');
_dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
if (!_dbus_string_insert_byte (&str, 0, 255))
if (!_dbus_string_insert_bytes (&str, 0, 1, 255))
_dbus_assert_not_reached ("can't insert byte");
if (!_dbus_string_insert_byte (&str, 2, 'Z'))
if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z'))
_dbus_assert_not_reached ("can't insert byte");
if (!_dbus_string_insert_byte (&str, _dbus_string_get_length (&str), 'W'))
if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W'))
_dbus_assert_not_reached ("can't insert byte");
_dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
_dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
_dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
_dbus_assert (_dbus_string_get_byte (&str, 3) == 'q');
_dbus_assert (_dbus_string_get_byte (&str, 4) == 'l');
_dbus_assert (_dbus_string_get_byte (&str, 5) == 'l');
_dbus_assert (_dbus_string_get_byte (&str, 6) == 'o');
_dbus_assert (_dbus_string_get_byte (&str, 7) == 'W');
_dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z');
_dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z');
_dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z');
_dbus_assert (_dbus_string_get_byte (&str, 6) == 'q');
_dbus_assert (_dbus_string_get_byte (&str, 7) == 'l');
_dbus_assert (_dbus_string_get_byte (&str, 8) == 'l');
_dbus_assert (_dbus_string_get_byte (&str, 9) == 'o');
_dbus_assert (_dbus_string_get_byte (&str, 10) == 'W');
_dbus_string_free (&str);
@ -3481,7 +3718,38 @@ _dbus_string_test (void)
/* Base 64 and Hex encoding */
test_roundtrips (test_base64_roundtrip);
test_roundtrips (test_hex_roundtrip);
/* Path validation */
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
{
_dbus_string_init_const (&str, valid_paths[i]);
if (!_dbus_string_validate_path (&str, 0,
_dbus_string_get_length (&str)))
{
_dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]);
_dbus_assert_not_reached ("invalid path");
}
++i;
}
i = 0;
while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
{
_dbus_string_init_const (&str, invalid_paths[i]);
if (_dbus_string_validate_path (&str, 0,
_dbus_string_get_length (&str)))
{
_dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]);
_dbus_assert_not_reached ("valid path");
}
++i;
}
return TRUE;
}

View file

@ -28,11 +28,15 @@
#include <dbus/dbus-memory.h>
#include <dbus/dbus-types.h>
#include <dbus/dbus-sysdeps.h>
#include <stdarg.h>
DBUS_BEGIN_DECLS;
typedef struct DBusString DBusString;
/**
* DBusString object
*/
struct DBusString
{
void *dummy1; /**< placeholder */
@ -68,8 +72,9 @@ void _dbus_string_set_byte (DBusString *str,
unsigned char byte);
unsigned char _dbus_string_get_byte (const DBusString *str,
int start);
dbus_bool_t _dbus_string_insert_byte (DBusString *str,
dbus_bool_t _dbus_string_insert_bytes (DBusString *str,
int i,
int n_bytes,
unsigned char byte);
dbus_bool_t _dbus_string_steal_data (DBusString *str,
char **data_return);
@ -111,6 +116,12 @@ dbus_bool_t _dbus_string_append_4_aligned (DBusString *str,
const unsigned char octets[4]);
dbus_bool_t _dbus_string_append_8_aligned (DBusString *str,
const unsigned char octets[8]);
dbus_bool_t _dbus_string_append_printf (DBusString *str,
const char *format,
...) _DBUS_GNUC_PRINTF (2, 3);
dbus_bool_t _dbus_string_append_printf_valist (DBusString *str,
const char *format,
va_list args);
void _dbus_string_delete (DBusString *str,
int start,
int len);
@ -216,7 +227,16 @@ dbus_bool_t _dbus_string_validate_utf8 (const DBusString *str,
dbus_bool_t _dbus_string_validate_nul (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_name (const DBusString *str,
dbus_bool_t _dbus_string_validate_path (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_interface (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_member (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_error_name (const DBusString *str,
int start,
int len);
dbus_bool_t _dbus_string_validate_service (const DBusString *str,

View file

@ -2515,9 +2515,12 @@ _dbus_path_is_absolute (const DBusString *filename)
return FALSE;
}
/**
* Internals of directory iterator
*/
struct DBusDirIter
{
DIR *d;
DIR *d; /**< The DIR* from opendir() */
};

View file

@ -25,7 +25,6 @@
#ifndef DBUS_SYSDEPS_H
#define DBUS_SYSDEPS_H
#include <dbus/dbus-string.h>
#include <dbus/dbus-errors.h>
/* this is perhaps bogus, but strcmp() etc. are faster if we use the
@ -47,6 +46,8 @@ DBUS_BEGIN_DECLS;
* dbus-memory.c)
*/
typedef struct DBusString DBusString;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
#define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) \
__attribute__((__format__ (__printf__, format_idx, arg_idx)))
@ -96,12 +97,14 @@ typedef unsigned long dbus_gid_t;
#define DBUS_UID_FORMAT "%lu"
#define DBUS_GID_FORMAT "%lu"
/**
* Struct representing socket credentials
*/
typedef struct
{
/* Set to DBUS_PID_UNSET etc. if not available */
dbus_pid_t pid;
dbus_uid_t uid;
dbus_gid_t gid;
dbus_pid_t pid; /**< process ID or DBUS_PID_UNSET */
dbus_uid_t uid; /**< user ID or DBUS_UID_UNSET */
dbus_gid_t gid; /**< group ID or DBUS_GID_UNSET */
} DBusCredentials;
int _dbus_connect_unix_socket (const char *path,
@ -134,6 +137,9 @@ dbus_bool_t _dbus_credentials_match (const DBusCredentials *expec
typedef struct DBusUserInfo DBusUserInfo;
typedef struct DBusGroupInfo DBusGroupInfo;
/**
* Information about a UNIX user
*/
struct DBusUserInfo
{
dbus_uid_t uid; /**< UID */
@ -144,6 +150,9 @@ struct DBusUserInfo
char *homedir; /**< Home directory */
};
/**
* Information about a UNIX group
*/
struct DBusGroupInfo
{
dbus_gid_t gid; /**< GID */
@ -172,9 +181,13 @@ dbus_uid_t _dbus_getuid (void);
dbus_gid_t _dbus_getgid (void);
typedef struct DBusAtomic DBusAtomic;
/**
* An atomic integer.
*/
struct DBusAtomic
{
volatile dbus_int32_t value;
volatile dbus_int32_t value; /**< Value of the atomic integer. */
};
dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic);
@ -187,11 +200,14 @@ dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic);
#define _DBUS_POLLHUP 0x0010 /* Hung up */
#define _DBUS_POLLNVAL 0x0020 /* Invalid request: fd not open */
/**
* A portable struct pollfd wrapper.
*/
typedef struct
{
int fd;
short events;
short revents;
int fd; /**< File descriptor */
short events; /**< Events to poll for */
short revents; /**< Events that occurred */
} DBusPollFD;
int _dbus_poll (DBusPollFD *fds,
@ -248,16 +264,19 @@ void _dbus_fd_set_close_on_exec (int fd);
void _dbus_exit (int code) _DBUS_GNUC_NORETURN;
/**
* Portable struct with stat() results
*/
typedef struct
{
unsigned long mode;
unsigned long nlink;
dbus_uid_t uid;
dbus_gid_t gid;
unsigned long size;
unsigned long atime;
unsigned long mtime;
unsigned long ctime;
unsigned long mode; /**< File mode */
unsigned long nlink; /**< Number of hard links */
dbus_uid_t uid; /**< User owning file */
dbus_gid_t gid; /**< Group owning file */
unsigned long size; /**< Size of file */
unsigned long atime; /**< Access time */
unsigned long mtime; /**< Modify time */
unsigned long ctime; /**< Creation time */
} DBusStat;
dbus_bool_t _dbus_stat (const DBusString *filename,

View file

@ -81,7 +81,7 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
die ("strings");
check_memleaks ();
printf ("%s: running sysdeps tests\n", "dbus-test");
if (!_dbus_sysdeps_test ())
die ("sysdeps");
@ -99,6 +99,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
die ("address parsing");
check_memleaks ();
printf ("%s: running object tree tests\n", "dbus-test");
if (!_dbus_object_tree_test ())
die ("object tree");
check_memleaks ();
printf ("%s: running marshalling tests\n", "dbus-test");
if (!_dbus_marshal_test ())
@ -129,12 +135,6 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
die ("messages");
check_memleaks ();
printf ("%s: running message handler tests\n", "dbus-test");
if (!_dbus_message_handler_test (test_data_dir))
die ("message handler");
check_memleaks ();
printf ("%s: running hash table tests\n", "dbus-test");
if (!_dbus_hash_test ())
@ -179,6 +179,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
die ("auth");
check_memleaks ();
printf ("%s: running pending call tests\n", "dbus-test");
if (!_dbus_pending_call_test (test_data_dir))
die ("auth");
check_memleaks ();
printf ("%s: completed successfully\n", "dbus-test");
#else

View file

@ -43,7 +43,6 @@ dbus_bool_t _dbus_mem_pool_test (void);
dbus_bool_t _dbus_string_test (void);
dbus_bool_t _dbus_address_test (void);
dbus_bool_t _dbus_message_test (const char *test_data_dir);
dbus_bool_t _dbus_message_handler_test (const char *test_data_dir);
dbus_bool_t _dbus_auth_test (const char *test_data_dir);
dbus_bool_t _dbus_md5_test (void);
dbus_bool_t _dbus_sha_test (const char *test_data_dir);
@ -53,7 +52,8 @@ dbus_bool_t _dbus_sysdeps_test (void);
dbus_bool_t _dbus_spawn_test (const char *test_data_dir);
dbus_bool_t _dbus_userdb_test (const char *test_data_dir);
dbus_bool_t _dbus_memory_test (void);
dbus_bool_t _dbus_object_tree_test (void);
dbus_bool_t _dbus_pending_call_test (const char *test_data_dir);
void dbus_internal_do_not_use_run_tests (const char *test_data_dir);
dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename,

View file

@ -223,10 +223,10 @@ init_global_locks (void)
#define LOCK_ADDR(name) (& _dbus_lock_##name)
LOCK_ADDR (list),
LOCK_ADDR (connection_slots),
LOCK_ADDR (pending_call_slots),
LOCK_ADDR (server_slots),
LOCK_ADDR (message_slots),
LOCK_ADDR (atomic),
LOCK_ADDR (message_handler),
LOCK_ADDR (bus),
LOCK_ADDR (shutdown_funcs),
LOCK_ADDR (system_users)

View file

@ -66,30 +66,34 @@ typedef enum
DBUS_THREAD_FUNCTIONS_ALL_MASK = (1 << 10) - 1
} DBusThreadFunctionsMask;
/**
* Functions that must be implemented to make the D-BUS
* library thread-aware.
*/
typedef struct
{
unsigned int mask;
unsigned int mask; /**< Mask indicating which functions are present. */
DBusMutexNewFunction mutex_new;
DBusMutexFreeFunction mutex_free;
DBusMutexLockFunction mutex_lock;
DBusMutexUnlockFunction mutex_unlock;
DBusMutexNewFunction mutex_new; /**< Function to create a mutex */
DBusMutexFreeFunction mutex_free; /**< Function to free a mutex */
DBusMutexLockFunction mutex_lock; /**< Function to lock a mutex */
DBusMutexUnlockFunction mutex_unlock; /**< Function to unlock a mutex */
DBusCondVarNewFunction condvar_new;
DBusCondVarFreeFunction condvar_free;
DBusCondVarWaitFunction condvar_wait;
DBusCondVarWaitTimeoutFunction condvar_wait_timeout;
DBusCondVarWakeOneFunction condvar_wake_one;
DBusCondVarWakeAllFunction condvar_wake_all;
DBusCondVarNewFunction condvar_new; /**< Function to create a condition variable */
DBusCondVarFreeFunction condvar_free; /**< Function to free a condition variable */
DBusCondVarWaitFunction condvar_wait; /**< Function to wait on a condition */
DBusCondVarWaitTimeoutFunction condvar_wait_timeout; /**< Function to wait on a condition with a timeout */
DBusCondVarWakeOneFunction condvar_wake_one; /**< Function to wake one thread waiting on the condition */
DBusCondVarWakeAllFunction condvar_wake_all; /**< Function to wake all threads waiting on the condition */
void (* padding1) (void);
void (* padding2) (void);
void (* padding3) (void);
void (* padding4) (void);
void (* padding5) (void);
void (* padding6) (void);
void (* padding7) (void);
void (* padding8) (void);
void (* padding1) (void); /**< Reserved for future expansion */
void (* padding2) (void); /**< Reserved for future expansion */
void (* padding3) (void); /**< Reserved for future expansion */
void (* padding4) (void); /**< Reserved for future expansion */
void (* padding5) (void); /**< Reserved for future expansion */
void (* padding6) (void); /**< Reserved for future expansion */
void (* padding7) (void); /**< Reserved for future expansion */
void (* padding8) (void); /**< Reserved for future expansion */
} DBusThreadFunctions;

View file

@ -33,6 +33,9 @@
* @{
*/
/**
* Internals of DBusTimeout
*/
struct DBusTimeout
{
int refcount; /**< Reference count */

View file

@ -34,6 +34,10 @@ DBUS_BEGIN_DECLS;
typedef struct DBusTransportVTable DBusTransportVTable;
/**
* The virtual table that must be implemented to
* create a new kind of transport.
*/
struct DBusTransportVTable
{
void (* finalize) (DBusTransport *transport);
@ -69,6 +73,12 @@ struct DBusTransportVTable
/**< Outstanding messages counter changed */
};
/**
* Object representing a transport such as a socket.
* A transport can shuttle messages from point A to point B,
* and is the backend for a #DBusConnection.
*
*/
struct DBusTransport
{
int refcount; /**< Reference count. */

View file

@ -813,7 +813,9 @@ _dbus_transport_queue_messages (DBusTransport *transport)
{
DBusDispatchStatus status;
#if 0
_dbus_verbose ("_dbus_transport_queue_messages()\n");
#endif
/* Queue any messages */
while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)

View file

@ -83,6 +83,10 @@ typedef dbus_uint32_t dbus_unichar_t;
*
* A 64-bit unsigned integer on all platforms that support it.
* If supported, #DBUS_HAVE_INT64 will be defined.
*
* C99 requires a 64-bit type and most likely all interesting
* compilers support one. GLib for example flat-out requires
* a 64-bit type.
*/
/**
@ -90,6 +94,10 @@ typedef dbus_uint32_t dbus_unichar_t;
*
* A 64-bit signed integer on all platforms that support it.
* If supported, #DBUS_HAVE_INT64 will be defined.
*
* C99 requires a 64-bit type and most likely all interesting
* compilers support one. GLib for example flat-out requires
* a 64-bit type.
*/
/**

View file

@ -26,14 +26,17 @@
#include "dbus-internals.h"
#include <string.h>
/**
* Internals of DBusUserDatabase
*/
struct DBusUserDatabase
{
int refcount;
int refcount; /**< Reference count */
DBusHashTable *users;
DBusHashTable *groups;
DBusHashTable *users_by_name;
DBusHashTable *groups_by_name;
DBusHashTable *users; /**< Users in the database by UID */
DBusHashTable *groups; /**< Groups in the database by GID */
DBusHashTable *users_by_name; /**< Users in the database by name */
DBusHashTable *groups_by_name; /**< Groups in the database by name */
};
static void

View file

@ -33,6 +33,9 @@
* @{
*/
/**
* Implementation of DBusWatch
*/
struct DBusWatch
{
int refcount; /**< Reference count */

View file

@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus.h Convenience header including all other headers
*
* Copyright (C) 2002 Red Hat Inc.
* Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
@ -37,7 +37,7 @@
#include <dbus/dbus-errors.h>
#include <dbus/dbus-macros.h>
#include <dbus/dbus-message.h>
#include <dbus/dbus-message-handler.h>
#include <dbus/dbus-pending-call.h>
#include <dbus/dbus-protocol.h>
#include <dbus/dbus-server.h>
#include <dbus/dbus-threads.h>

View file

@ -23,9 +23,6 @@
(changing get_string to have an error return, and allowing a type error
as a possible return)
- We might consider returning a "no such operation" error in dbus-connection.c
for unhandled messages.
- The convenience functions in dbus-bus.h should perhaps have
the signatures that they would have if they were autogenerated
stubs. e.g. the acquire service function. We should also evaluate
@ -69,3 +66,30 @@
files; they have to be in the toplevel file. when loading
a child file, we could just init its DBusLimits from the parent,
then after parsing copy its DBusLimits back to the parent
- when making a method call, if the call serial were globally unique,
we could forward the call serial along with any method calls made
as a result of the first method call, and allow reentrancy that was
strictly part of the call stack of said method call. But I don't
really see how to do this without making the user pass around the
call serial to all method calls all the time, or disallowing
async calls.
- the invalid messages in the test suite are all useless because
they are invalid for the wrong reasons due to protocol changes
- I don't want to introduce DBusObject, but refcounting and object
data could still be factored out into an internal "base class"
perhaps.
- modify the auth protocol to also support other initial-handshake
type of information
- document the auth protocol as a set of states and transitions, and
then reimplement it in those terms
- dbus_gproxy or dbus_g_proxy?
- add dbus_message_has_path(), maybe has_member/interface
- The OBJECT_PATH type is not documented in the spec.

View file

@ -3,8 +3,8 @@
<article id="index">
<artheader>
<title>D-BUS Specification</title>
<releaseinfo>Version 0.7</releaseinfo>
<date>26 March 2003</date>
<releaseinfo>Version 0.8</releaseinfo>
<date>06 September 2003</date>
<authorgroup>
<author>
<firstname>Havoc</firstname>
@ -65,10 +65,10 @@
<para>
D-BUS is <emphasis>easy to use</emphasis> because it works in terms
of <firstterm>messages</firstterm> rather than byte streams, and
does not require users to understand any complex concepts such as a
new type system or elaborate APIs. Libraries implementing D-BUS
may choose to abstract messages as "method calls" (see
<xref linkend="message-conventions-method">).
automatically handles a lot of the hard IPC issues. Also, the D-BUS
library is designed to be wrapped in a way that lets developers use
their framework's existing object/type system, rather than learning
a new one specifically for IPC.
</para>
</listitem>
</itemizedlist>
@ -83,11 +83,10 @@
forwards messages among them.
</para>
<para>
Things that D-BUS can be used for is for example notification of
system changes (notification of when a camera is plugged in to a
computer, or a new version of some software has been installed),
or desktop interoperablity, for example a file monitoring
service or a configuration service.
Uses of D-BUS include notification of system changes (notification of when
a camera is plugged in to a computer, or a new version of some software
has been installed), or desktop interoperablity, for example a file
monitoring service or a configuration service.
</para>
</sect1>
@ -133,6 +132,12 @@
<entry>Endianness flag; ASCII 'l' for little-endian
or ASCII 'B' for big-endian.</entry>
</row>
<row>
<entry>1 byte</entry>
<entry>Type of message. Unknown types MUST be ignored.
Currently-defined types are described below.
</entry>
</row>
<row>
<entry>1 byte</entry>
<entry>Bitwise OR of flags. Unknown flags
@ -148,12 +153,6 @@
version for this version of the specification is 0.
</entry>
</row>
<row>
<entry>1 byte</entry>
<entry>A nul byte, reserved for future use.
Any value for this byte MUST be accepted.
</entry>
</row>
<row>
<entry>4 bytes</entry>
<entry>An unsigned 32-bit integer in the
@ -172,9 +171,11 @@
<row>
<entry>4 bytes</entry>
<entry>The message's serial number, an unsigned 32-bit integer in
the message's byte order. Applications MUST NOT reuse the same
serial number for different messages more often than 32-bit
unsigned integer wraparound. Zero is not a valid serial number.
the message's byte order. The serial number is a cookie used to
identify message replies; thus all outstanding unreplied-to messages
from the same connection MUST have a different serial number.
Zero is not a valid serial number, but all other numbers are
allowed.
</entry>
</row>
</tbody>
@ -182,19 +183,67 @@
</informaltable>
</para>
<para>
Flags that can appear in the second byte of the header:
Types that can appear in the second byte of the header:
<informaltable>
<tgroup cols=2>
<tgroup cols=3>
<thead>
<row>
<entry>Conventional name</entry>
<entry>Decimal value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>INVALID</entry>
<entry>0</entry>
<entry>This is an invalid type, if seen in a message
the connection should be dropped immediately.</entry>
</row>
<row>
<entry>METHOD_CALL</entry>
<entry>1</entry>
<entry>Method call.</entry>
</row>
<row>
<entry>METHOD_RETURN</entry>
<entry>2</entry>
<entry>Method reply with returned data.</entry>
</row>
<row>
<entry>ERROR</entry>
<entry>3</entry>
<entry>Error reply. If the first argument exists and is a
string, it is an error message.</entry>
</row>
<row>
<entry>SIGNAL</entry>
<entry>4</entry>
<entry>Signal emission.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
Flags that can appear in the third byte of the header:
<informaltable>
<tgroup cols=3>
<thead>
<row>
<entry>Conventional name</entry>
<entry>Hex value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>NO_REPLY_EXPECTED</entry>
<entry>0x1</entry>
<entry>This message is an error reply. If the first argument exists and is a string, it is an error message.</entry>
<entry>This message does not expect method return replies or
error replies; the reply can be omitted as an
optimization. However, it is compliant with this specification
to return the reply despite this flag.</entry>
</row>
</tbody>
</tgroup>
@ -208,22 +257,21 @@
In addition to the required header information mentioned
in <xref linkend="message-protocol-header-encoding">,
the header may contain zero or more named
header fields. These fields are named to allow
future versions of this protocol specification to
add new fields; implementations must ignore fields
they do not understand. Implementations must not
invent their own header fields; only changes to
header fields. Future versions of this protocol
specification may add new fields. Implementations must
ignore fields they do not understand. Implementations
must not invent their own header fields; only changes to
this specification may introduce new header fields.
</para>
<para>
Header field names MUST consist of 4 non-nul bytes. The field name is
NOT nul terminated; it occupies exactly 4 bytes. Following the name, the
field MUST have a type code represented as a single unsigned byte, and
then a properly-aligned value of that type. See <xref
linkend="message-protocol-arguments"> for a description of how each type
is encoded. If an implementation sees a header field name that it does
not understand, it MUST ignore that field.
Header field names MUST consist of a single byte, possible values
of which are defined below. Following the name, the field MUST have
a type code represented as a single unsigned byte, and then a
properly-aligned value of that type. See <xref
linkend="message-protocol-arguments"> for a description of how each
type is encoded. If an implementation sees a header field name that
it does not understand, it MUST ignore that field.
</para>
<para>
@ -232,36 +280,68 @@
<tgroup cols=3>
<thead>
<row>
<entry>Name</entry>
<entry>Conventional Name</entry>
<entry>Decimal Value</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>name</entry>
<entry>STRING</entry>
<entry>The name of the message, such as org.freedesktop.Peer.Ping</entry>
<entry>INVALID</entry>
<entry>0</entry>
<entry>INVALID</entry>
<entry>Not a valid field name (error if it appears in a message)</entry>
</row>
<row>
<entry>rply</entry>
<entry>PATH</entry>
<entry>1</entry>
<entry>STRING</entry>
<entry>The object to send the message to; objects are identified by
a path, "/foo/bar"</entry>
</row>
<row>
<entry>INTERFACE</entry>
<entry>2</entry>
<entry>STRING</entry>
<entry>The interface to invoke a method call on, or
that a signal is emitted from. e.g. "org.freedesktop.Introspectable"</entry>
</row>
<row>
<entry>MEMBER</entry>
<entry>3</entry>
<entry>STRING</entry>
<entry>The member, either the method name or signal name.
e.g. "Frobate"</entry>
</row>
<row>
<entry>ERROR_NAME</entry>
<entry>4</entry>
<entry>STRING</entry>
<entry>The name of the error that occurred, for errors</entry>
</row>
<row>
<entry>REPLY_SERIAL</entry>
<entry>5</entry>
<entry>UINT32</entry>
<entry>The serial number of the message this message is a reply
to. (The serial number is one of the mandatory header fields,
see <xref linkend="message-protocol-header-encoding">.)</entry>
</row>
<row>
<entry>srvc</entry>
<entry>SERVICE</entry>
<entry>6</entry>
<entry>STRING</entry>
<entry>The name of the service this message should be routed to.
Only used in combination with the message bus, see
<xref linkend="message-bus">.</entry>
</row>
<row>
<entry>sndr</entry>
<entry>SENDER_SERVICE</entry>
<entry>7</entry>
<entry>STRING</entry>
<entry>The name of the base service that sent this message.
The message bus fills in this field; the field is
<entry>Sender service. The name of the base service that sent
this message. The message bus fills in this field; the field is
only meaningful in combination with the message bus.</entry>
</row>
</tbody>
@ -277,10 +357,9 @@
buffer while keeping data types aligned, the total length of the header
must be a multiple of 8 bytes. To achieve this, the header MUST be padded
with nul bytes to align its total length on an 8-byte boundary.
The minimum number of padding bytes MUST be used. Because all possible
named fields use at least 8 bytes, implementations can distinguish
padding (which must be less than 8 bytes) from additional named fields
(which must be at least 8 bytes).
The minimum number of padding bytes MUST be used. Because zero is an
invalid field name, implementations can distinguish padding (which must be
zero initialized) from additional named fields.
</para>
</sect2>
@ -440,19 +519,228 @@
<sect2 id="message-protocol-names">
<title>Valid names</title>
<para>
Messages and services have names with type STRING, meaning that
they must be valid UTF-8. However, there are also some
additional restrictions that apply to message and service names
specifically:
<itemizedlist>
<listitem><para>They must contain at least one '.' (period) character</para></listitem>
<listitem><para>They must not begin with a '.' (period) character</para></listitem>
<listitem><para>They must not exceed 256 bytes in length</para></listitem>
<listitem><para>They must be at least 1 byte in length</para></listitem>
</itemizedlist>
As a special exception, base service names (those beginning with a colon (':') character)
need not contain a period.
The various header fields of type STRING have some restrictions
on the string's format.
</para>
<sect3 id="message-protocol-names-service">
<title>Service names</title>
<para>
Services have names with type STRING, meaning that
they must be valid UTF-8. However, there are also some
additional restrictions that apply to service names
specifically:
<itemizedlist>
<listitem><para>They must contain at least one '.' (period) character</para></listitem>
<listitem><para>They must not begin with a '.' (period) character</para></listitem>
<listitem><para>They must not exceed 256 bytes in length</para></listitem>
<listitem><para>They must be at least 1 byte in length</para></listitem>
</itemizedlist>
As a special exception, base service names (those beginning with a colon
(':') character) need not contain a period.
</para>
<para>
FIXME really, shouldn't we ban basically everything non-alphanumeric
so the name will work in all programming languages?
</para>
</sect3>
<sect3 id="message-protocol-names-interface">
<title>Interface names</title>
<para>
Interface names have the same restrictions as service names,
but do not have the special exception for names beginning with
a colon.
</para>
<para>
FIXME really, shouldn't we ban basically everything non-alphanumeric
so the name will work in all programming languages?
</para>
</sect3>
<sect3 id="message-protocol-names-method">
<title>Method names</title>
<para>
Method names:
<itemizedlist>
<listitem><para>May not contain the '.' (period) character</para></listitem>
<listitem><para>Must not exceed 256 bytes in length</para></listitem>
<listitem><para>Must be at least 1 byte in length</para></listitem>
</itemizedlist>
</para>
<para>
FIXME really, shouldn't we ban basically everything non-alphanumeric
so the name will work in all programming languages?
</para>
</sect3>
<sect3 id="message-protocol-names-path">
<title>Path names</title>
<para>
A path must begin with an ASCII '/' (slash) character. Paths may not
end with a slash character unless the path is the one-byte string
"/". Two slash characters may not appear adjacent to one another (the
empty string is not a valid "subdirectory"). Paths may not exceed
256 bytes in length.
</para>
</sect3>
<sect3 id="message-protocol-names-error">
<title>Error names</title>
<para>
Error names have the same restrictions as interface names.
</para>
<para>
FIXME really, shouldn't we ban basically everything non-alphanumeric
so the name will work in all programming languages?
</para>
</sect3>
</sect2>
<sect2 id="message-protocol-types">
<title>Message types</title>
<para>
Each of the message types (METHOD_CALL, METHOD_RETURN, ERROR, and
SIGNAL) has its own expected usage conventions and header fields.
</para>
<sect3 id="message-protocol-types-method">
<title>Method Calls, Returns, and Errors</title>
<para>
Some messages invoke an operation on a remote object. These are
called method call messages and have the type tag METHOD_CALL. Such
messages map naturally to methods on objects in a typical program.
</para>
<para>
A method call message is expected to have a MEMBER header field
indicating the name of the method. Optionally, the message has an
INTERFACE field giving the interface the method is a part of. In the
absence of an INTERFACE field, if two interfaces on the same object have
a method with the same name, it is undefined which of the two methods
will be invoked. Implementations may also choose to return an error in
this ambiguous case. However, if a method name is unique
implementations should not require an interface field.
</para>
<para>
Method call messages also include a PATH field indicating the
object to invoke the method on. If the call is passing through
a message bus, the message will also have a SERVICE field giving
the service to receive the message.
</para>
<para>
When an application handles a method call message, it is expected to
return a reply. The reply is identified by a REPLY_SERIAL header field
indicating the serial number of the METHOD_CALL being replied to. The
reply can have one of two types; either METHOD_RETURN or ERROR.
</para>
<para>
If the reply has type METHOD_RETURN, the arguments to the reply message
are the return value(s) or "out parameters" of the method call.
If the reply has type ERROR, then an "exception" has been thrown,
and the call fails; no return value will be provided. It makes
no sense to send multiple replies to the same method call.
</para>
<para>
Even if a method call has no return values, a METHOD_RETURN
reply is expected, so the caller will know the method
was successfully processed.
</para>
<para>
If a METHOD_CALL message has the flag NO_REPLY_EXPECTED,
then as an optimization the application receiving the method
call may choose to omit the reply message (regardless of
whether the reply would have been METHOD_RETURN or ERROR).
However, it is also acceptable to ignore the NO_REPLY_EXPECTED
flag and reply anyway.
</para>
<sect4 id="message-protocol-types-method-apis">
<title>Mapping method calls to native APIs</title>
<para>
APIs for D-BUS may map method calls to a method call in a specific
programming language, such as C++, or may map a method call written
in an IDL to a D-BUS message.
</para>
<para>
In APIs of this nature, arguments to a method are often termed "in"
(which implies sent in the METHOD_CALL), or "out" (which implies
returned in the METHOD_RETURN). Some APIs such as CORBA also have
"inout" arguments, which are both sent and received, i.e. the caller
passes in a value which is modified. Mapped to D-BUS, an "inout"
argument is equivalent to an "in" argument, followed by an "out"
argument. You can't pass things "by reference" over the wire, so
"inout" is purely an illusion of the in-process API.
</para>
<para>
Given a method with zero or one return values, followed by zero or more
arguments, where each argument may be "in", "out", or "inout", the
caller constructs a message by appending each "in" or "inout" argument,
in order. "out" arguments are not represented in the caller's message.
</para>
<para>
The recipient constructs a reply by appending first the return value
if any, then each "out" or "inout" argument, in order.
"in" arguments are not represented in the reply message.
</para>
</sect4>
</sect3>
<sect3 id="message-protocol-types-signal">
<title>Signal Emission</title>
<para>
Unlike method calls, signal emissions have no replies.
A signal emission is simply a single message of type SIGNAL.
It must have three header fields: PATH giving the object
the signal was emitted from, plus INTERFACE and MEMBER giving
the fully-qualified name of the signal.
</para>
</sect3>
<sect3 id="message-protocol-types-notation">
<title>Notation in this document</title>
<para>
This document uses a simple pseudo-IDL to describe particular method
calls and signals. Here is an example of a method call:
<programlisting>
org.freedesktop.DBus.ActivateService (in STRING service_name, in UINT32 flags,
out UINT32 resultcode)
</programlisting>
This means INTERFACE = org.freedesktop.DBus, MEMBER = ActivateService,
METHOD_CALL arguments are STRING and UINT32, METHOD_RETURN argument
is UINT32. Remember that the MEMBER field can't contain any '.' (period)
characters so it's known that the last part of the name in
the "IDL" is the member name.
</para>
<para>
In C++ that might end up looking like this:
<programlisting>
unsigned int org::freedesktop::DBus::ActivateService (const char *service_name,
unsigned int flags);
</programlisting>
or equally valid, the return value could be done as an argument:
<programlisting>
void org::freedesktop::DBus::ActivateService (const char *service_name,
unsigned int flags,
unsigned int *resultcode);
</programlisting>
It's really up to the API designer how they want to make
this look. You could design an API where the namespace wasn't used
in C++, using STL or Qt, using varargs, or whatever you wanted.
</para>
<para>
Signals are written as follows:
<programlisting>
org.freedesktop.DBus.ServiceLost (STRING service_name)
</programlisting>
Signals don't specify "in" vs. "out" because only
a single direction is possible.
</para>
<para>
In this ad hoc notation, the special type name ANY means any type
other than NIL, and the special type name ANY_OR_NIL means any valid
type.
</para>
<para>
It isn't especially encouraged to use this lame pseudo-IDL in actual
API implementations; you might use the native notation for the
language you're using, or you might use COM or CORBA IDL, for example.
</para>
</sect3>
</sect2>
</sect1>
@ -730,6 +1018,13 @@
</figure>
</para>
</sect2>
<sect2 id="auth-states">
<title>Authentication state diagrams</title>
<para>
WRITEME
</para>
</sect2>
<sect2 id="auth-mechanisms">
<title>Authentication mechanisms</title>
<para>
@ -905,161 +1200,35 @@
</para>
</sect1>
<sect1 id="message-conventions">
<title>Message Conventions</title>
<para>
This section documents conventions that are not essential to D-BUS
functionality, but should generally be followed in order to simplify
programmer's lives.
</para>
<sect2 id="message-conventions-naming">
<title>Message Naming</title>
<para>
Messages are normally named in the form
"org.freedesktop.Peer.Ping", which has three
distinct components:
<variablelist>
<varlistentry>
<term>Namespace e.g. <literal>org.freedesktop</literal></term>
<listitem>
<para>
Message names have a Java-style namespace: a reversed domain
name. The components of the domain are normally lowercase.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Package or object e.g. <literal>Peer</literal></term>
<listitem>
<para>
The next part of the message name can be thought of as the name
of a singleton object, or as the name of a package of related
messages. More than one dot-separated component might be used
here. (Note that D-BUS does not define any idea of object
instances or object references.) The package or object name is
capitalized LikeThis.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Method or operation e.g. <literal>Ping</literal></term>
<listitem>
<para>
The final part of the message name is the most specific, and
should be a verb indicating an operation to be performed on the
object. The method or operation name is capitalized LikeThis.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
A reply to a message conventionally has the same name as the message
being replied to. When following method call conventions (see <xref
linkend="message-conventions-method">), this convention is mandatory,
because a message with multiple possible replies can't be mapped
to method call semantics without special-case code.
</para>
</sect2>
<sect2 id="message-conventions-method">
<title>Method Call Mapping</title>
<para>
Some implementations of D-BUS may present an API that translates object
method calls into D-BUS messages. This document does not specify in
detail how such an API should look or work. However, it does specify how
message-based protocols should be designed to be friendly to such an
API.
</para>
<para>
Remember that D-BUS does not have object references or object instances.
So when one application sends the message
<literal>org.freedesktop.Peer.Ping</literal>, it sends it to another
application, not to any kind of sub-portion of that application.
However, a convenience API used within the recipient application may
route all messages that start with
<literal>org.freedesktop.Peer</literal> to a particular object instance,
and may invoke the <literal>Ping()</literal> method on said instance in
order to handle the message. This is a convenience API based on
method calls.
</para>
<para>
A "method call" consists of a message and, optionally, a reply to that
message. The name of the "method" is the last component of the message,
for example, <literal>org.freedesktop.Peer.Ping</literal> would map to
the method <literal>Ping()</literal> on some object.
</para>
<para>
Arguments to a method may be considered "in" (processed by the
recipient of the message), or "out" (returned to the sender of the
message in the reply). "inout" arguments are both sent and received,
i.e. the caller passes in a value which is modified. An "inout" argument
is equivalent to an "in" argument, followed by an "out" argument.
</para>
<para>
Given a method with zero or one return values, followed by zero or more
arguments, where each argument may be "in", "out", or "inout", the
caller constructs a message by appending each "in" or "inout" argument,
in order. "out" arguments are not represented in the caller's message.
</para>
<para>
The recipient constructs a reply by appending first the return value
if any, then each "out" or "inout" argument, in order.
"in" arguments are not represented in the reply message.
</para>
<para>
The standard reply message MUST have the same name as the message being
replied to, and MUST set the "rply" header field to the serial
number of the message being replied to.
</para>
<para>
If an error occurs, an error reply may be sent in place of the standard
reply. Error replies can be identified by a special header flag, see
<xref linkend="message-protocol-header-encoding">. Error replies have a
name which reflects the type of error that occurred. Error replies would
generally be mapped to exceptions in a programming language. If an
error reply has a first argument, and that argument has type STRING,
then the argument must be an error message.
</para>
<para>
[FIXME discuss mapping of broadcast messages + matching rules
to signals and slots]
</para>
</sect2>
</sect1>
<sect1 id="standard-messages">
<title>Standard Peer-to-Peer Messages</title>
<para>
In the following message definitions, "method call notation" is presented
in addition to simply listing the message names and arguments. The special
type name ANY means any type other than NIL, and the special type name
ANY_OR_NIL means any valid type.
[FIXME the messages here are just made up to illustrate the
format for defining them]
See <xref linkend="message-protocol-types-notation"> for details on
the notation used in this section.
</para>
<sect2 id="standard-messages-ping">
<title><literal>org.freedesktop.Peer.Ping</literal></title>
<para>
As a method:
<programlisting>
void Ping ()
org.freedesktop.Peer.Ping ()
</programlisting>
</para>
<para>
On receipt of the message <literal>org.freedesktop.Peer.Ping</literal>,
an application should reply with
<literal>org.freedesktop.Peer.Ping</literal>. Neither the
message nor its reply have any arguments.
[FIXME the messages here are just made up to illustrate the
format for defining them]
On receipt of the METHOD_CALL
message <literal>org.freedesktop.Peer.Ping</literal>, an application
should do nothing other than reply with a METHOD_RETURN as usual.
</para>
</sect2>
<sect2 id="standard-messages-get-props">
<title><literal>org.freedesktop.Props.Get</literal></title>
<para>
As a method:
[FIXME this is just a bogus made-up method that isn't implemented
or thought through, to save an example of table formatting for the
argument descriptions]
<programlisting>
ANY_OR_NIL Get (in STRING property_name)
org.freedesktop.Props.Get (in STRING property_name,
out ANY_OR_NIL property_value)
</programlisting>
Message arguments:
<informaltable>
@ -1074,37 +1243,18 @@
<tbody>
<row>
<entry>0</entry>
<entry>STRING</entry>
<entry>in STRING</entry>
<entry>Name of the property to get</entry>
</row>
</tbody>
</tgroup>
</informaltable>
Reply arguments:
<informaltable>
<tgroup cols=3>
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>ANY_OR_NIL</entry>
<entry>1</entry>
<entry>out ANY_OR_NIL</entry>
<entry>The value of the property. The type depends on the property.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
[FIXME the messages here are just made up to illustrate the
format for defining them]
</para>
</sect2>
</sect1>
@ -1132,18 +1282,18 @@
the new owner of the service.
</para>
<para>
Messages may have a <literal>srvc</literal> field (see <xref
Messages may have a <literal>SERVICE</literal> field (see <xref
linkend="message-protocol-header-fields">). When the message bus
receives a message, if the <literal>srvc</literal> field is absent, the
receives a message, if the <literal>SERVICE</literal> field is absent, the
message is taken to be a standard peer-to-peer message and interpreted
by the message bus itself. For example, sending
an <literal>org.freedesktop.Peer.Ping</literal> message with no
<literal>srvc</literal> will cause the message bus itself to reply
<literal>SERVICE</literal> will cause the message bus itself to reply
to the ping immediately; the message bus would never make
this message visible to other applications.
</para>
<para>
If the <literal>srvc</literal> field is present, then it indicates a
If the <literal>SERVICE</literal> field is present, then it indicates a
request for the message bus to route the message. In the usual case,
messages are routed to the owner of the named service.
Messages may also be <firstterm>broadcast</firstterm>
@ -1154,7 +1304,7 @@
</para>
<para>
Continuing the <literal>org.freedesktop.Peer.Ping</literal> example, if
the ping message were sent with a <literal>srvc</literal> name of
the ping message were sent with a <literal>SERVICE</literal> name of
<literal>com.yoyodyne.Screensaver</literal>, then the ping would be
forwarded, and the Yoyodyne Corporation screensaver application would be
expected to reply to the ping. If
@ -1967,6 +2117,32 @@
</para>
</glossdef>
</glossentry>
<glossentry id="term-object"><glossterm>Object</glossterm>
<glossdef>
<para>
Each application contains <firstterm>objects</firstterm>,
which have <firstterm>interfaces</firstterm> and
<firstterm>methods</firstterm>. Objects are referred to
by a name, called a <firstterm>path</firstterm> or
<firstterm>object reference</firstterm>.
</para>
</glossdef>
</glossentry>
<glossentry id="term-path"><glossterm>Path</glossterm>
<glossdef>
<para>
Object references (object names) in D-BUS are
organized into a filesystem-style hierarchy, so
each object is named by a path. As in LDAP,
there's no difference between "files" and "directories";
a path can refer to an object, while still having
child objects below it.
</para>
</glossdef>
</glossentry>
<glossentry id="peer-to-peer"><glossterm>Peer-to-peer</glossterm>
<glossdef>
<para>

View file

@ -4,11 +4,9 @@ Makefile
Makefile.in
*.lo
*.la
test-dbus-glib
dbus-glib-test
dbus-glib-tool
*.bb
*.bbg
*.da
*.gcov
test-thread-client
test-thread-server
test-profile

View file

@ -1,4 +1,4 @@
INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS)
INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) -DDBUS_COMPILATION=1
dbusincludedir=$(includedir)/dbus-1.0/dbus
@ -9,47 +9,61 @@ dbusinclude_HEADERS= \
libdbus_glib_1_la_SOURCES = \
dbus-gmain.c \
dbus-gthread.c
dbus-gobject.c \
dbus-gproxy.c \
dbus-gtest.c \
dbus-gtest.h \
dbus-gthread.c \
dbus-gutils.c \
dbus-gutils.h
libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la
## don't export symbols that start with "_" (we use this
## convention for internal symbols)
libdbus_glib_1_la_LDFLAGS= -export-symbols-regex "^[^_].*"
# convenience lib used here and by dbus-viewer
noinst_LTLIBRARIES=libdbus-gtool.la
libdbus_gtool_la_SOURCES = \
dbus-gidl.c \
dbus-gidl.h \
dbus-gloader-expat.c \
dbus-gparser.c \
dbus-gparser.h \
dbus-gutils.c \
dbus-gutils.h
libdbus_gtool_la_LIBADD = libdbus-glib-1.la
bin_PROGRAMS=dbus-glib-tool
dbus_glib_tool_SOURCES = \
dbus-glib-tool.c \
dbus-gtool-test.h
dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-gtool.la
if DBUS_BUILD_TESTS
if HAVE_GLIB_THREADS
THREAD_APPS=test-thread-server test-thread-client test-profile
## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we
## build even when not doing "make check"
noinst_PROGRAMS= $(TESTS)
test_thread_server_SOURCES= \
test-thread-server.c \
test-thread.h
## note that TESTS has special meaning (stuff to use in make check)
## so if adding tests not to be run in make check, don't add them to
## TESTS
TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus
TESTS=dbus-glib-test
test_thread_server_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la
dbus_glib_test_SOURCES= \
dbus-gtest-main.c
test_thread_client_SOURCES= \
test-thread-client.c \
test-thread.h
test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la
endif
noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS)
test_dbus_glib_SOURCES= \
test-dbus-glib.c
test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
dbus_glib_test_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
else
### not building tests
if HAVE_GLIB_THREADS
noinst_PROGRAMS=test-profile
endif
TESTS=
endif
if HAVE_GLIB_THREADS
test_profile_SOURCES= \
test-profile.c
test_profile_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la
endif

524
glib/dbus-gidl.c Normal file
View file

@ -0,0 +1,524 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gidl.c data structure describing an interface, to be generated from IDL
* or something
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-gidl.h"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
struct BaseInfo
{
unsigned int refcount : 28;
unsigned int type : 4;
char *name;
};
struct NodeInfo
{
BaseInfo base;
GSList *interfaces;
GSList *nodes;
};
struct InterfaceInfo
{
BaseInfo base;
/* Since we have BaseInfo now these could be one list */
GSList *methods;
GSList *signals;
};
struct MethodInfo
{
BaseInfo base;
GSList *args;
};
struct SignalInfo
{
BaseInfo base;
GSList *args;
};
struct ArgInfo
{
BaseInfo base;
int type;
ArgDirection direction;
};
void
base_info_ref (BaseInfo *info)
{
g_return_if_fail (info != NULL);
g_return_if_fail (info->refcount > 0);
info->refcount += 1;
}
static void
base_info_free (void *ptr)
{
BaseInfo *info;
info = ptr;
g_free (info->name);
g_free (info);
}
void
base_info_unref (BaseInfo *info)
{
g_return_if_fail (info != NULL);
g_return_if_fail (info->refcount > 0);
/* This is sort of bizarre, BaseInfo was tacked on later */
switch (info->type)
{
case INFO_TYPE_NODE:
node_info_unref ((NodeInfo*) info);
break;
case INFO_TYPE_INTERFACE:
interface_info_unref ((InterfaceInfo*) info);
break;
case INFO_TYPE_SIGNAL:
signal_info_unref ((SignalInfo*) info);
break;
case INFO_TYPE_METHOD:
method_info_unref ((MethodInfo*) info);
break;
case INFO_TYPE_ARG:
arg_info_unref ((ArgInfo*) info);
break;
}
}
InfoType
base_info_get_type (BaseInfo *info)
{
return info->type;
}
const char*
base_info_get_name (BaseInfo *info)
{
return info->name;
}
void
base_info_set_name (BaseInfo *info,
const char *name)
{
char *old;
old = info->name;
info->name = g_strdup (name);
g_free (old);
}
GType
base_info_get_gtype (void)
{
static GType our_type = 0;
if (our_type == 0)
our_type = g_boxed_type_register_static ("BaseInfo",
(GBoxedCopyFunc) base_info_ref,
(GBoxedFreeFunc) base_info_unref);
return our_type;
}
static void
free_interface_list (GSList **interfaces_p)
{
GSList *tmp;
tmp = *interfaces_p;
while (tmp != NULL)
{
interface_info_unref (tmp->data);
tmp = tmp->next;
}
g_slist_free (*interfaces_p);
*interfaces_p = NULL;
}
static void
free_node_list (GSList **nodes_p)
{
GSList *tmp;
tmp = *nodes_p;
while (tmp != NULL)
{
node_info_unref (tmp->data);
tmp = tmp->next;
}
g_slist_free (*nodes_p);
*nodes_p = NULL;
}
static void
free_method_list (GSList **methods_p)
{
GSList *tmp;
tmp = *methods_p;
while (tmp != NULL)
{
method_info_unref (tmp->data);
tmp = tmp->next;
}
g_slist_free (*methods_p);
*methods_p = NULL;
}
static void
free_signal_list (GSList **signals_p)
{
GSList *tmp;
tmp = *signals_p;
while (tmp != NULL)
{
signal_info_unref (tmp->data);
tmp = tmp->next;
}
g_slist_free (*signals_p);
*signals_p = NULL;
}
NodeInfo*
node_info_new (const char *name)
{
NodeInfo *info;
/* name can be NULL */
info = g_new0 (NodeInfo, 1);
info->base.refcount = 1;
info->base.name = g_strdup (name);
info->base.type = INFO_TYPE_NODE;
return info;
}
void
node_info_ref (NodeInfo *info)
{
info->base.refcount += 1;
}
void
node_info_unref (NodeInfo *info)
{
info->base.refcount -= 1;
if (info->base.refcount == 0)
{
free_interface_list (&info->interfaces);
free_node_list (&info->nodes);
base_info_free (info);
}
}
const char*
node_info_get_name (NodeInfo *info)
{
return info->base.name;
}
GSList*
node_info_get_interfaces (NodeInfo *info)
{
return info->interfaces;
}
void
node_info_add_interface (NodeInfo *info,
InterfaceInfo *interface)
{
interface_info_ref (interface);
info->interfaces = g_slist_append (info->interfaces, interface);
}
GSList*
node_info_get_nodes (NodeInfo *info)
{
return info->nodes;
}
void
node_info_add_node (NodeInfo *info,
NodeInfo *node)
{
node_info_ref (node);
info->nodes = g_slist_append (info->nodes, node);
}
InterfaceInfo*
interface_info_new (const char *name)
{
InterfaceInfo *info;
info = g_new0 (InterfaceInfo, 1);
info->base.refcount = 1;
info->base.name = g_strdup (name);
info->base.type = INFO_TYPE_INTERFACE;
return info;
}
void
interface_info_ref (InterfaceInfo *info)
{
info->base.refcount += 1;
}
void
interface_info_unref (InterfaceInfo *info)
{
info->base.refcount -= 1;
if (info->base.refcount == 0)
{
free_method_list (&info->methods);
free_signal_list (&info->signals);
base_info_free (info);
}
}
const char*
interface_info_get_name (InterfaceInfo *info)
{
return info->base.name;
}
GSList*
interface_info_get_methods (InterfaceInfo *info)
{
return info->methods;
}
GSList*
interface_info_get_signals (InterfaceInfo *info)
{
return info->signals;
}
void
interface_info_add_method (InterfaceInfo *info,
MethodInfo *method)
{
method_info_ref (method);
info->methods = g_slist_append (info->methods, method);
}
void
interface_info_add_signal (InterfaceInfo *info,
SignalInfo *signal)
{
signal_info_ref (signal);
info->signals = g_slist_append (info->signals, signal);
}
static void
free_arg_list (GSList **args_p)
{
GSList *tmp;
tmp = *args_p;
while (tmp != NULL)
{
arg_info_unref (tmp->data);
tmp = tmp->next;
}
g_slist_free (*args_p);
*args_p = NULL;
}
MethodInfo*
method_info_new (const char *name)
{
MethodInfo *info;
info = g_new0 (MethodInfo, 1);
info->base.refcount = 1;
info->base.name = g_strdup (name);
info->base.type = INFO_TYPE_METHOD;
return info;
}
void
method_info_ref (MethodInfo *info)
{
info->base.refcount += 1;
}
void
method_info_unref (MethodInfo *info)
{
info->base.refcount -= 1;
if (info->base.refcount == 0)
{
free_arg_list (&info->args);
base_info_free (info);
}
}
const char*
method_info_get_name (MethodInfo *info)
{
return info->base.name;
}
GSList*
method_info_get_args (MethodInfo *info)
{
return info->args;
}
void
method_info_add_arg (MethodInfo *info,
ArgInfo *arg)
{
arg_info_ref (arg);
info->args = g_slist_append (info->args, arg);
}
SignalInfo*
signal_info_new (const char *name)
{
SignalInfo *info;
info = g_new0 (SignalInfo, 1);
info->base.refcount = 1;
info->base.name = g_strdup (name);
info->base.type = INFO_TYPE_SIGNAL;
return info;
}
void
signal_info_ref (SignalInfo *info)
{
info->base.refcount += 1;
}
void
signal_info_unref (SignalInfo *info)
{
info->base.refcount -= 1;
if (info->base.refcount == 0)
{
free_arg_list (&info->args);
base_info_free (info);
}
}
const char*
signal_info_get_name (SignalInfo *info)
{
return info->base.name;
}
GSList*
signal_info_get_args (SignalInfo *info)
{
return info->args;
}
void
signal_info_add_arg (SignalInfo *info,
ArgInfo *arg)
{
arg_info_ref (arg);
info->args = g_slist_append (info->args, arg);
}
ArgInfo*
arg_info_new (const char *name,
ArgDirection direction,
int type)
{
ArgInfo *info;
info = g_new0 (ArgInfo, 1);
info->base.refcount = 1;
info->base.type = INFO_TYPE_ARG;
/* name can be NULL */
info->base.name = g_strdup (name);
info->direction = direction;
info->type = type;
return info;
}
void
arg_info_ref (ArgInfo *info)
{
info->base.refcount += 1;
}
void
arg_info_unref (ArgInfo *info)
{
info->base.refcount -= 1;
if (info->base.refcount == 0)
{
base_info_free (info);
}
}
const char*
arg_info_get_name (ArgInfo *info)
{
return info->base.name;
}
int
arg_info_get_type (ArgInfo *info)
{
return info->type;
}
ArgDirection
arg_info_get_direction (ArgInfo *info)
{
return info->direction;
}
#ifdef DBUS_BUILD_TESTS
/**
* @ingroup DBusGIDL
* Unit test for GLib IDL internals
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_gidl_test (void)
{
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

120
glib/dbus-gidl.h Normal file
View file

@ -0,0 +1,120 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gidl.h data structure describing an interface, to be generated from IDL
* or something
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_GLIB_IDL_H
#define DBUS_GLIB_IDL_H
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <dbus/dbus.h>
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct BaseInfo BaseInfo;
typedef struct NodeInfo NodeInfo;
typedef struct InterfaceInfo InterfaceInfo;
typedef struct MethodInfo MethodInfo;
typedef struct SignalInfo SignalInfo;
typedef struct ArgInfo ArgInfo;
typedef enum
{
ARG_IN,
ARG_OUT
} ArgDirection;
typedef enum
{
INFO_TYPE_NODE,
INFO_TYPE_INTERFACE,
INFO_TYPE_METHOD,
INFO_TYPE_SIGNAL,
INFO_TYPE_ARG
} InfoType;
void base_info_ref (BaseInfo *info);
void base_info_unref (BaseInfo *info);
InfoType base_info_get_type (BaseInfo *info);
const char* base_info_get_name (BaseInfo *info);
void base_info_set_name (BaseInfo *info,
const char *name);
GType base_info_get_gtype (void);
#define BASE_INFO_TYPE (base_info_get_gtype ())
NodeInfo* node_info_new (const char *name);
void node_info_ref (NodeInfo *info);
void node_info_unref (NodeInfo *info);
const char* node_info_get_name (NodeInfo *info);
GSList* node_info_get_interfaces (NodeInfo *info);
GSList* node_info_get_nodes (NodeInfo *info);
void node_info_add_interface (NodeInfo *info,
InterfaceInfo *interface);
void node_info_add_node (NodeInfo *info,
NodeInfo *child);
InterfaceInfo* interface_info_new (const char *name);
void interface_info_ref (InterfaceInfo *info);
void interface_info_unref (InterfaceInfo *info);
const char* interface_info_get_name (InterfaceInfo *info);
GSList* interface_info_get_methods (InterfaceInfo *info);
GSList* interface_info_get_signals (InterfaceInfo *info);
void interface_info_add_method (InterfaceInfo *info,
MethodInfo *method);
void interface_info_add_signal (InterfaceInfo *info,
SignalInfo *signal);
MethodInfo* method_info_new (const char *name);
void method_info_ref (MethodInfo *info);
void method_info_unref (MethodInfo *info);
const char* method_info_get_name (MethodInfo *info);
GSList* method_info_get_args (MethodInfo *info);
void method_info_add_arg (MethodInfo *info,
ArgInfo *arg);
SignalInfo* signal_info_new (const char *name);
void signal_info_ref (SignalInfo *info);
void signal_info_unref (SignalInfo *info);
const char* signal_info_get_name (SignalInfo *info);
GSList* signal_info_get_args (SignalInfo *info);
void signal_info_add_arg (SignalInfo *info,
ArgInfo *arg);
ArgInfo* arg_info_new (const char *name,
ArgDirection direction,
int type);
void arg_info_ref (ArgInfo *info);
void arg_info_unref (ArgInfo *info);
const char* arg_info_get_name (ArgInfo *info);
int arg_info_get_type (ArgInfo *info);
ArgDirection arg_info_get_direction (ArgInfo *info);
G_END_DECLS
#endif /* DBUS_GLIB_IDL_H */
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

77
glib/dbus-glib-tool.c Normal file
View file

@ -0,0 +1,77 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-compiler-main.c main() for GLib stubs/skels generator
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-gidl.h"
#include <locale.h>
#ifdef DBUS_BUILD_TESTS
static void run_all_tests (const char *test_data_dir);
#endif
int
main (int argc, char **argv)
{
setlocale(LC_ALL, "");
return 0;
}
#ifdef DBUS_BUILD_TESTS
static void
test_die (const char *failure)
{
fprintf (stderr, "Unit test failed: %s\n", failure);
exit (1);
}
static void
run_all_tests (const char *test_data_dir)
{
if (test_data_dir == NULL)
test_data_dir = _dbus_getenv ("DBUS_TEST_DATA");
if (test_data_dir != NULL)
printf ("Test data in %s\n", test_data_dir);
else
printf ("No test data!\n");
printf ("%s: running gtool tests\n", "dbus-glib-tool");
if (!_dbus_gtool_test (test_data_dir))
test_die ("gtool");
printf ("%s: completed successfully\n", "dbus-glib-test");
}
/**
* @ingroup DBusGTool
* Unit test for GLib utility tool
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_gtool_test (const char *test_data_dir)
{
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */

View file

@ -2,6 +2,7 @@
/* dbus-glib.h GLib integration
*
* Copyright (C) 2002, 2003 CodeFactory AB
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
@ -24,16 +25,132 @@
#define DBUS_GLIB_H
#include <dbus/dbus.h>
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
void dbus_gthread_init (void);
#define DBUS_INSIDE_DBUS_GLIB_H 1
GQuark dbus_g_error_quark (void);
#define DBUS_GERROR dbus_g_error_quark ()
#define DBUS_TYPE_CONNECTION (dbus_connection_get_g_type ())
#define DBUS_TYPE_MESSAGE (dbus_message_get_g_type ())
GType dbus_connection_get_g_type (void) G_GNUC_CONST;
GType dbus_message_get_g_type (void) G_GNUC_CONST;
typedef enum
{
/* FIXME map all the DBUS_ERROR to DBUS_GERROR, should
* probably be automated in some way, perhaps
* via lame perl script
*/
DBUS_GERROR_FAILED
} DBusGError;
void dbus_set_g_error (GError **gerror,
DBusError *derror);
void dbus_g_thread_init (void);
void dbus_connection_setup_with_g_main (DBusConnection *connection,
GMainContext *context);
void dbus_server_setup_with_g_main (DBusServer *server,
GMainContext *context);
typedef struct DBusGObjectInfo DBusGObjectInfo;
typedef struct DBusGMethodInfo DBusGMethodInfo;
/**
* Object typically generated by dbus-glib-tool that
* stores a mapping from introspection data to a
* function pointer for a C method to be invoked.
*/
struct DBusGMethodInfo
{
GCallback function; /**< C method to invoke */
DBusHandleMessageFunction marshaller; /**< Marshaller to go DBusMessage to C method */
int data_offset; /**< Offset into the introspection data */
};
/**
* Introspection data for a GObject, normally autogenerated by
* a tool such as dbus-glib-tool.
*/
struct DBusGObjectInfo
{
const DBusGMethodInfo *infos; /**< Array of method pointers */
const unsigned char *data; /**< Introspection data */
void *dbus_internal_padding1; /**< Reserved for expansion */
void *dbus_internal_padding2; /**< Reserved for expansion */
};
void dbus_g_object_class_install_info (GObjectClass *object_class,
const DBusGObjectInfo *info);
void dbus_connection_register_g_object (DBusConnection *connection,
const char *at_path,
GObject *object);
typedef struct DBusGProxy DBusGProxy;
typedef struct DBusGProxyClass DBusGProxyClass;
typedef void (* DBusGProxySignalHandler) (DBusGProxy *proxy,
DBusMessage *signal,
void *user_data);
#define DBUS_TYPE_GPROXY (dbus_gproxy_get_type ())
#define DBUS_GPROXY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), DBUS_TYPE_GPROXY, DBusGProxy))
#define DBUS_GPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DBUS_TYPE_GPROXY, DBusGProxyClass))
#define DBUS_IS_GPROXY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), DBUS_TYPE_GPROXY))
#define DBUS_IS_GPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUS_TYPE_GPROXY))
#define DBUS_GPROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUS_TYPE_GPROXY, DBusGProxyClass))
GType dbus_gproxy_get_type (void) G_GNUC_CONST;
DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection,
const char *service_name,
const char *path_name,
const char *interface_name);
DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection,
const char *service_name,
const char *path_name,
const char *interface_name,
GError **error);
DBusGProxy* dbus_gproxy_new_for_peer (DBusConnection *connection,
const char *path_name,
const char *interface_name);
void dbus_gproxy_connect_signal (DBusGProxy *proxy,
const char *signal_name,
DBusGProxySignalHandler handler,
void *data,
GClosureNotify free_data_func);
void dbus_gproxy_disconnect_signal (DBusGProxy *proxy,
const char *signal_name,
DBusGProxySignalHandler handler,
void *data);
DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy,
const char *method,
int first_arg_type,
...);
gboolean dbus_gproxy_end_call (DBusGProxy *proxy,
DBusPendingCall *pending,
GError **error,
int first_arg_type,
...);
void dbus_gproxy_oneway_call (DBusGProxy *proxy,
const char *method,
int first_arg_type,
...);
void dbus_gproxy_send (DBusGProxy *proxy,
DBusMessage *message,
dbus_uint32_t *client_serial);
#undef DBUS_INSIDE_DBUS_GLIB_H
G_END_DECLS
#endif /* DBUS_GLIB_H */

262
glib/dbus-gloader-expat.c Normal file
View file

@ -0,0 +1,262 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gloader-expat.c expat XML loader
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-gparser.h"
#include <expat.h>
static void*
expat_g_malloc (size_t sz)
{
return g_malloc (sz);
}
static void*
expat_g_realloc (void *mem, size_t sz)
{
return g_realloc (mem, sz);
}
static XML_Memory_Handling_Suite memsuite =
{
expat_g_malloc,
expat_g_realloc,
g_free
};
/**
* Context for Expat parser for introspection data.
*/
typedef struct
{
Parser *parser; /**< The parser for the introspection data */
const char *filename; /**< The filename being loaded */
GString *content; /**< The content of the current element */
GError **error; /**< Error return location */
gboolean failed; /**< True if parse has failed */
} ExpatParseContext;
static dbus_bool_t
process_content (ExpatParseContext *context)
{
if (context->failed)
return FALSE;
if (context->content->len > 0)
{
if (!parser_content (context->parser,
context->content->str,
context->content->len,
context->error))
{
context->failed = TRUE;
return FALSE;
}
g_string_set_size (context->content, 0);
}
return TRUE;
}
static void
expat_StartElementHandler (void *userData,
const XML_Char *name,
const XML_Char **atts)
{
ExpatParseContext *context = userData;
int i;
char **names;
char **values;
/* Expat seems to suck and can't abort the parse if we
* throw an error. Expat 2.0 is supposed to fix this.
*/
if (context->failed)
return;
if (!process_content (context))
return;
/* "atts" is key, value, key, value, NULL */
for (i = 0; atts[i] != NULL; ++i)
; /* nothing */
g_assert (i % 2 == 0);
names = g_new0 (char *, i / 2 + 1);
values = g_new0 (char *, i / 2 + 1);
i = 0;
while (atts[i] != NULL)
{
g_assert (i % 2 == 0);
names [i / 2] = (char*) atts[i];
values[i / 2] = (char*) atts[i+1];
i += 2;
}
if (!parser_start_element (context->parser,
name,
(const char **) names,
(const char **) values,
context->error))
{
g_free (names);
g_free (values);
context->failed = TRUE;
return;
}
g_free (names);
g_free (values);
}
static void
expat_EndElementHandler (void *userData,
const XML_Char *name)
{
ExpatParseContext *context = userData;
if (!process_content (context))
return;
if (!parser_end_element (context->parser,
name,
context->error))
{
context->failed = TRUE;
return;
}
}
/* s is not 0 terminated. */
static void
expat_CharacterDataHandler (void *userData,
const XML_Char *s,
int len)
{
ExpatParseContext *context = userData;
if (context->failed)
return;
g_string_append_len (context->content,
s, len);
}
NodeInfo*
description_load_from_file (const char *filename,
GError **error)
{
char *contents;
gsize len;
NodeInfo *nodes;
contents = NULL;
if (!g_file_get_contents (filename, &contents, &len, error))
return NULL;
nodes = description_load_from_string (contents, len, error);
g_free (contents);
return nodes;
}
NodeInfo*
description_load_from_string (const char *str,
int len,
GError **error)
{
XML_Parser expat;
ExpatParseContext context;
NodeInfo *nodes;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
expat = NULL;
context.parser = NULL;
context.error = error;
context.failed = FALSE;
expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
if (expat == NULL)
g_error ("No memory to create XML parser\n");
context.parser = parser_new ();
context.content = g_string_new (NULL);
XML_SetUserData (expat, &context);
XML_SetElementHandler (expat,
expat_StartElementHandler,
expat_EndElementHandler);
XML_SetCharacterDataHandler (expat,
expat_CharacterDataHandler);
if (!XML_Parse (expat, str, len, TRUE))
{
if (context.error != NULL &&
*context.error == NULL)
{
enum XML_Error e;
e = XML_GetErrorCode (expat);
if (e == XML_ERROR_NO_MEMORY)
g_error ("Not enough memory to parse XML document");
else
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
"Error in D-BUS description XML, line %d, column %d: %s\n",
XML_GetCurrentLineNumber (expat),
XML_GetCurrentColumnNumber (expat),
XML_ErrorString (e));
}
goto failed;
}
if (context.failed)
goto failed;
if (!parser_finished (context.parser, error))
goto failed;
XML_ParserFree (expat);
g_string_free (context.content, TRUE);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
nodes = parser_get_nodes (context.parser);
node_info_ref (nodes);
parser_unref (context.parser);
return nodes;
failed:
g_return_val_if_fail (error == NULL || *error != NULL, NULL);
g_string_free (context.content, TRUE);
if (expat)
XML_ParserFree (expat);
if (context.parser)
parser_unref (context.parser);
return NULL;
}

View file

@ -21,8 +21,13 @@
*
*/
#include <config.h>
#include "dbus-glib.h"
#include <glib.h>
#include "dbus-gtest.h"
#include <libintl.h>
#define _(x) dgettext (GETTEXT_PACKAGE, x)
#define N_(x) x
/**
* @defgroup DBusGLib GLib bindings
@ -48,6 +53,9 @@
*/
typedef struct DBusGSource DBusGSource;
/**
* A GSource subclass for a DBusConnection.
*/
struct DBusGSource
{
GSource source; /**< the parent GSource */
@ -530,4 +538,94 @@ dbus_server_setup_with_g_main (DBusServer *server,
g_error ("Not enough memory to set up DBusServer for use with GLib");
}
/**
* The implementation of DBUS_GERROR error domain. See documentation
* for GError in GLib reference manual.
*
* @returns the error domain quark for use with GError
*/
GQuark
dbus_g_error_quark (void)
{
static GQuark quark = 0;
if (quark == 0)
quark = g_quark_from_static_string ("g-exec-error-quark");
return quark;
}
/**
* Set a GError return location from a DBusError.
*
* @todo expand the DBUS_GERROR enum and take advantage of it here
*
* @param gerror location to store a GError, or #NULL
* @param derror the DBusError
*/
void
dbus_set_g_error (GError **gerror,
DBusError *derror)
{
g_return_if_fail (derror != NULL);
g_return_if_fail (dbus_error_is_set (derror));
g_set_error (gerror, DBUS_GERROR,
DBUS_GERROR_FAILED,
_("D-BUS error %s: %s"),
derror->name, derror->message);
}
/**
* Get the GLib type ID for a DBusConnection boxed type.
*
* @returns GLib type
*/
GType
dbus_connection_get_g_type (void)
{
static GType our_type = 0;
if (our_type == 0)
our_type = g_boxed_type_register_static ("DBusConnection",
(GBoxedCopyFunc) dbus_connection_ref,
(GBoxedFreeFunc) dbus_connection_unref);
return our_type;
}
/**
* Get the GLib type ID for a DBusMessage boxed type.
*
* @returns GLib type
*/
GType
dbus_message_get_g_type (void)
{
static GType our_type = 0;
if (our_type == 0)
our_type = g_boxed_type_register_static ("DBusMessage",
(GBoxedCopyFunc) dbus_message_ref,
(GBoxedFreeFunc) dbus_message_unref);
return our_type;
}
/** @} */ /* end of public API */
#ifdef DBUS_BUILD_TESTS
/**
* @ingroup DBusGLibInternals
* Unit test for GLib main loop integration
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_gmain_test (const char *test_data_dir)
{
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */

790
glib/dbus-gobject.c Normal file
View file

@ -0,0 +1,790 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gobject.c Exporting a GObject remotely
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include "dbus-glib.h"
#include "dbus-gtest.h"
#include "dbus-gutils.h"
#include <string.h>
/**
* @addtogroup DBusGLibInternals
* @{
*/
static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT;
static GHashTable *info_hash = NULL;
static char*
wincaps_to_uscore (const char *caps)
{
const char *p;
GString *str;
str = g_string_new (NULL);
p = caps;
while (*p)
{
if (g_ascii_isupper (*p))
{
if (str->len > 0 &&
(str->len < 2 || str->str[str->len-2] != '_'))
g_string_append_c (str, '_');
g_string_append_c (str, g_ascii_tolower (*p));
}
else
{
g_string_append_c (str, *p);
}
++p;
}
return g_string_free (str, FALSE);
}
static char*
uscore_to_wincaps (const char *uscore)
{
const char *p;
GString *str;
gboolean last_was_uscore;
last_was_uscore = TRUE;
str = g_string_new (NULL);
p = uscore;
while (*p)
{
if (*p == '-' || *p == '_')
{
last_was_uscore = TRUE;
}
else
{
if (last_was_uscore)
{
g_string_append_c (str, g_ascii_toupper (*p));
last_was_uscore = FALSE;
}
else
g_string_append_c (str, *p);
}
++p;
}
return g_string_free (str, FALSE);
}
static void
gobject_unregister_function (DBusConnection *connection,
void *user_data)
{
GObject *object;
object = G_OBJECT (user_data);
/* FIXME */
}
static int
gtype_to_dbus_type (GType type)
{
switch (type)
{
case G_TYPE_CHAR:
case G_TYPE_UCHAR:
return DBUS_TYPE_BYTE;
case G_TYPE_BOOLEAN:
return DBUS_TYPE_BOOLEAN;
/* long gets cut to 32 bits so the remote API is consistent
* on all architectures
*/
case G_TYPE_LONG:
case G_TYPE_INT:
return DBUS_TYPE_INT32;
case G_TYPE_ULONG:
case G_TYPE_UINT:
return DBUS_TYPE_UINT32;
case G_TYPE_INT64:
return DBUS_TYPE_INT64;
case G_TYPE_UINT64:
return DBUS_TYPE_UINT64;
case G_TYPE_FLOAT:
case G_TYPE_DOUBLE:
return DBUS_TYPE_DOUBLE;
case G_TYPE_STRING:
return DBUS_TYPE_STRING;
default:
return DBUS_TYPE_INVALID;
}
}
static const char *
dbus_type_to_string (int type)
{
switch (type)
{
case DBUS_TYPE_INVALID:
return "invalid";
case DBUS_TYPE_NIL:
return "nil";
case DBUS_TYPE_BOOLEAN:
return "boolean";
case DBUS_TYPE_INT32:
return "int32";
case DBUS_TYPE_UINT32:
return "uint32";
case DBUS_TYPE_DOUBLE:
return "double";
case DBUS_TYPE_STRING:
return "string";
case DBUS_TYPE_NAMED:
return "named";
case DBUS_TYPE_ARRAY:
return "array";
case DBUS_TYPE_DICT:
return "dict";
default:
return "unknown";
}
}
static DBusHandlerResult
handle_introspect (DBusConnection *connection,
DBusMessage *message,
GObject *object)
{
GString *xml;
GParamSpec **specs;
unsigned int n_specs;
unsigned int i;
GType last_type;
DBusMessage *ret;
char **path;
char **children;
if (!dbus_message_get_path_decomposed (message, &path))
g_error ("Out of memory");
if (!dbus_connection_list_registered (connection, (const char**) path,
&children))
g_error ("Out of memory");
xml = g_string_new (NULL);
g_string_append (xml, "<node>\n");
last_type = G_TYPE_INVALID;
specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
&n_specs);
i = 0;
while (i < n_specs)
{
GParamSpec *spec = specs[i];
gboolean can_set;
gboolean can_get;
char *s;
int dbus_type;
dbus_type = gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec));
if (dbus_type == DBUS_TYPE_INVALID)
goto next;
if (spec->owner_type != last_type)
{
if (last_type != G_TYPE_INVALID)
g_string_append (xml, " </interface>\n");
/* FIXME what should the namespace on the interface be in
* general? should people be able to set it for their
* objects?
*/
g_string_append (xml, " <interface name=\"org.gtk.objects.");
g_string_append (xml, g_type_name (spec->owner_type));
g_string_append (xml, "\">\n");
last_type = spec->owner_type;
}
can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
(spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
can_get = (spec->flags & G_PARAM_READABLE) != 0;
s = uscore_to_wincaps (spec->name);
if (can_set)
{
g_string_append (xml, " <method name=\"set_");
g_string_append (xml, s);
g_string_append (xml, "\">\n");
g_string_append (xml, " <arg type=\"");
g_string_append (xml, dbus_type_to_string (dbus_type));
g_string_append (xml, "\"/>\n");
}
if (can_get)
{
g_string_append (xml, " <method name=\"get_");
g_string_append (xml, s);
g_string_append (xml, "\">\n");
g_string_append (xml, " <arg type=\"");
g_string_append (xml, dbus_type_to_string (dbus_type));
g_string_append (xml, "\" direction=\"out\"/>\n");
}
g_free (s);
next:
++i;
}
if (last_type != G_TYPE_INVALID)
g_string_append (xml, " </interface>\n");
g_free (specs);
/* Append child nodes */
i = 0;
while (children[i])
{
g_string_append_printf (xml, " <node name=\"%s\"/>\n",
children[i]);
++i;
}
/* Close the XML, and send it to the requesting app */
g_string_append (xml, "</node>\n");
ret = dbus_message_new_method_return (message);
if (ret == NULL)
g_error ("Out of memory");
dbus_message_append_args (message,
DBUS_TYPE_STRING, xml->str,
DBUS_TYPE_INVALID);
dbus_connection_send (connection, message, NULL);
dbus_message_unref (message);
g_string_free (xml, TRUE);
dbus_free_string_array (path);
dbus_free_string_array (children);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusMessage*
set_object_property (DBusConnection *connection,
DBusMessage *message,
GObject *object,
GParamSpec *pspec)
{
GValue value;
DBusMessageIter iter;
int type;
gboolean can_set;
DBusMessage *ret;
dbus_message_iter_init (message, &iter);
type = dbus_message_get_type (message);
can_set = TRUE;
switch (type)
{
case DBUS_TYPE_BYTE:
{
unsigned char b;
b = dbus_message_iter_get_byte (&iter);
g_value_init (&value, G_TYPE_UCHAR);
g_value_set_uchar (&value, b);
}
break;
case DBUS_TYPE_BOOLEAN:
{
gboolean b;
b = dbus_message_iter_get_boolean (&iter);
g_value_init (&value, G_TYPE_BOOLEAN);
g_value_set_boolean (&value, b);
}
break;
case DBUS_TYPE_INT32:
{
gint32 i;
i = dbus_message_iter_get_int32 (&iter);
g_value_init (&value, G_TYPE_INT);
g_value_set_int (&value, i);
}
break;
case DBUS_TYPE_UINT32:
{
guint32 i;
i = dbus_message_iter_get_uint32 (&iter);
g_value_init (&value, G_TYPE_UINT);
g_value_set_uint (&value, i);
}
break;
case DBUS_TYPE_INT64:
{
gint64 i;
i = dbus_message_iter_get_int64 (&iter);
g_value_init (&value, G_TYPE_INT64);
g_value_set_int64 (&value, i);
}
break;
case DBUS_TYPE_UINT64:
{
guint64 i;
i = dbus_message_iter_get_uint64 (&iter);
g_value_init (&value, G_TYPE_UINT64);
g_value_set_uint64 (&value, i);
}
break;
case DBUS_TYPE_DOUBLE:
{
double d;
d = dbus_message_iter_get_double (&iter);
g_value_init (&value, G_TYPE_DOUBLE);
g_value_set_double (&value, d);
}
break;
case DBUS_TYPE_STRING:
{
char *s;
/* FIXME use a const string accessor */
s = dbus_message_iter_get_string (&iter);
g_value_init (&value, G_TYPE_STRING);
g_value_set_string (&value, s);
g_free (s);
}
break;
/* FIXME array and other types, especially byte array
* converted to G_TYPE_STRING
*/
default:
can_set = FALSE;
break;
}
/* The g_object_set_property() will transform some types, e.g. it
* will let you use a uchar to set an int property etc. Note that
* any error in value range or value conversion will just
* g_warning(). These GObject skels are not for secure applications.
*/
if (can_set)
{
g_object_set_property (object,
pspec->name,
&value);
ret = dbus_message_new_method_return (message);
if (ret == NULL)
g_error ("out of memory");
g_value_unset (&value);
}
else
{
ret = dbus_message_new_error (message,
DBUS_ERROR_INVALID_ARGS,
"Argument's D-BUS type can't be converted to a GType");
if (ret == NULL)
g_error ("out of memory");
}
return ret;
}
static DBusMessage*
get_object_property (DBusConnection *connection,
DBusMessage *message,
GObject *object,
GParamSpec *pspec)
{
GType value_type;
gboolean can_get;
DBusMessage *ret;
GValue value;
DBusMessageIter iter;
value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
ret = dbus_message_new_method_return (message);
if (ret == NULL)
g_error ("out of memory");
can_get = TRUE;
g_value_init (&value, value_type);
g_object_get_property (object, pspec->name, &value);
value_type = G_VALUE_TYPE (&value);
dbus_message_append_iter_init (message, &iter);
switch (value_type)
{
case G_TYPE_CHAR:
dbus_message_iter_append_byte (&iter,
g_value_get_char (&value));
break;
case G_TYPE_UCHAR:
dbus_message_iter_append_byte (&iter,
g_value_get_uchar (&value));
break;
case G_TYPE_BOOLEAN:
dbus_message_iter_append_boolean (&iter,
g_value_get_boolean (&value));
break;
case G_TYPE_INT:
dbus_message_iter_append_int32 (&iter,
g_value_get_int (&value));
break;
case G_TYPE_UINT:
dbus_message_iter_append_uint32 (&iter,
g_value_get_uint (&value));
break;
/* long gets cut to 32 bits so the remote API is consistent
* on all architectures
*/
case G_TYPE_LONG:
dbus_message_iter_append_int32 (&iter,
g_value_get_long (&value));
break;
case G_TYPE_ULONG:
dbus_message_iter_append_uint32 (&iter,
g_value_get_ulong (&value));
break;
case G_TYPE_INT64:
dbus_message_iter_append_int64 (&iter,
g_value_get_int64 (&value));
break;
case G_TYPE_UINT64:
dbus_message_iter_append_uint64 (&iter,
g_value_get_uint64 (&value));
break;
case G_TYPE_FLOAT:
dbus_message_iter_append_double (&iter,
g_value_get_float (&value));
break;
case G_TYPE_DOUBLE:
dbus_message_iter_append_double (&iter,
g_value_get_double (&value));
break;
case G_TYPE_STRING:
/* FIXME, the GValue string may not be valid UTF-8 */
dbus_message_iter_append_string (&iter,
g_value_get_string (&value));
break;
default:
can_get = FALSE;
break;
}
g_value_unset (&value);
if (!can_get)
{
dbus_message_unref (ret);
ret = dbus_message_new_error (message,
DBUS_ERROR_UNKNOWN_METHOD,
"Can't convert GType of object property to a D-BUS type");
}
return ret;
}
static DBusHandlerResult
gobject_message_function (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
const DBusGObjectInfo *info;
GParamSpec *pspec;
GObject *object;
const char *member;
gboolean setter;
gboolean getter;
char *s;
object = G_OBJECT (user_data);
if (dbus_message_is_method_call (message,
DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
"Introspect"))
return handle_introspect (connection, message, object);
member = dbus_message_get_member (message);
/* Try the metainfo, which lets us invoke methods */
g_static_mutex_lock (&info_hash_mutex);
/* FIXME this needs to walk up the inheritance tree, not
* just look at the most-derived class
*/
info = g_hash_table_lookup (info_hash,
G_OBJECT_GET_CLASS (object));
g_static_mutex_unlock (&info_hash_mutex);
if (info != NULL)
{
}
/* If no metainfo, we can still do properties and signals
* via standard GLib introspection
*/
setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
if (!(setter || getter))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
s = wincaps_to_uscore (&member[4]);
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
s);
g_free (s);
if (pspec != NULL)
{
DBusMessage *ret;
if (setter)
{
ret = set_object_property (connection, message,
object, pspec);
}
else if (getter)
{
ret = get_object_property (connection, message,
object, pspec);
}
else
{
g_assert_not_reached ();
ret = NULL;
}
g_assert (ret != NULL);
dbus_connection_send (connection, ret, NULL);
dbus_message_unref (ret);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusObjectPathVTable gobject_dbus_vtable = {
gobject_unregister_function,
gobject_message_function,
NULL
};
/** @} */ /* end of internals */
/**
* @addtogroup DBusGLib
* @{
*/
/**
* Install introspection information about the given object class
* sufficient to allow methods on the object to be invoked by name.
* The introspection information is normally generated by
* dbus-glib-tool, then this function is called in the
* class_init() for the object class.
*
* Once introspection information has been installed, instances of the
* object registered with dbus_connection_register_g_object() can have
* their methods invoked remotely.
*
* @param object_class class struct of the object
* @param info introspection data generated by dbus-glib-tool
*/
void
dbus_g_object_class_install_info (GObjectClass *object_class,
const DBusGObjectInfo *info)
{
g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
g_static_mutex_lock (&info_hash_mutex);
if (info_hash == NULL)
{
info_hash = g_hash_table_new (NULL, NULL); /* direct hash */
}
g_hash_table_replace (info_hash, object_class, (void*) info);
g_static_mutex_unlock (&info_hash_mutex);
}
/**
* Registers a GObject at the given path. Properties, methods, and signals
* of the object can then be accessed remotely. Methods are only available
* if method introspection data has been added to the object's class
* with g_object_class_install_info().
*
* The registration will be cancelled if either the DBusConnection or
* the GObject gets finalized.
*
* @param connection the D-BUS connection
* @param at_path the path where the object will live (the object's name)
* @param object the object
*/
void
dbus_connection_register_g_object (DBusConnection *connection,
const char *at_path,
GObject *object)
{
char **split;
g_return_if_fail (connection != NULL);
g_return_if_fail (at_path != NULL);
g_return_if_fail (G_IS_OBJECT (object));
split = _dbus_gutils_split_path (at_path);
if (!dbus_connection_register_object_path (connection,
(const char**) split,
&gobject_dbus_vtable,
object))
g_error ("Failed to register GObject with DBusConnection");
g_strfreev (split);
/* FIXME set up memory management (so we break the
* registration if object or connection vanishes)
*/
}
/** @} */ /* end of public API */
#ifdef DBUS_BUILD_TESTS
#include <stdlib.h>
/**
* @ingroup DBusGLibInternals
* Unit test for GLib GObject integration ("skeletons")
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_gobject_test (const char *test_data_dir)
{
int i;
static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
{ "SetFoo", "set_foo" },
{ "Foo", "foo" },
{ "GetFooBar", "get_foo_bar" },
{ "Hello", "hello" }
/* Impossible-to-handle cases */
/* { "FrobateUIHandler", "frobate_ui_handler" } */
};
i = 0;
while (i < (int) G_N_ELEMENTS (name_pairs))
{
char *uscore;
char *wincaps;
uscore = wincaps_to_uscore (name_pairs[i].wincaps);
wincaps = uscore_to_wincaps (name_pairs[i].uscore);
if (strcmp (uscore, name_pairs[i].uscore) != 0)
{
g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
name_pairs[i].wincaps, name_pairs[i].uscore,
uscore);
exit (1);
}
if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
{
g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
name_pairs[i].uscore, name_pairs[i].wincaps,
wincaps);
exit (1);
}
g_free (uscore);
g_free (wincaps);
++i;
}
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */

670
glib/dbus-gparser.c Normal file
View file

@ -0,0 +1,670 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gparser.c parse DBus description files
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-gparser.h"
#include "dbus-gidl.h"
#include <string.h>
#include <libintl.h>
#define _(x) gettext ((x))
#define N_(x) x
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
typedef struct
{
const char *name;
const char **retloc;
} LocateAttr;
static gboolean
locate_attributes (const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error,
const char *first_attribute_name,
const char **first_attribute_retloc,
...)
{
va_list args;
const char *name;
const char **retloc;
int n_attrs;
#define MAX_ATTRS 24
LocateAttr attrs[MAX_ATTRS];
gboolean retval;
int i;
g_return_val_if_fail (first_attribute_name != NULL, FALSE);
g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
retval = TRUE;
n_attrs = 1;
attrs[0].name = first_attribute_name;
attrs[0].retloc = first_attribute_retloc;
*first_attribute_retloc = NULL;
va_start (args, first_attribute_retloc);
name = va_arg (args, const char*);
retloc = va_arg (args, const char**);
while (name != NULL)
{
g_return_val_if_fail (retloc != NULL, FALSE);
g_assert (n_attrs < MAX_ATTRS);
attrs[n_attrs].name = name;
attrs[n_attrs].retloc = retloc;
n_attrs += 1;
*retloc = NULL;
name = va_arg (args, const char*);
retloc = va_arg (args, const char**);
}
va_end (args);
if (!retval)
return retval;
i = 0;
while (attribute_names[i])
{
int j;
gboolean found;
found = FALSE;
j = 0;
while (j < n_attrs)
{
if (strcmp (attrs[j].name, attribute_names[i]) == 0)
{
retloc = attrs[j].retloc;
if (*retloc != NULL)
{
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Attribute \"%s\" repeated twice on the same <%s> element"),
attrs[j].name, element_name);
retval = FALSE;
goto out;
}
*retloc = attribute_values[i];
found = TRUE;
}
++j;
}
if (!found)
{
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Attribute \"%s\" is invalid on <%s> element in this context"),
attribute_names[i], element_name);
retval = FALSE;
goto out;
}
++i;
}
out:
return retval;
}
static gboolean
check_no_attributes (const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error)
{
if (attribute_names[0] != NULL)
{
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Attribute \"%s\" is invalid on <%s> element in this context"),
attribute_names[0], element_name);
return FALSE;
}
return TRUE;
}
struct Parser
{
int refcount;
NodeInfo *result; /* Filled in when we pop the last node */
GSList *node_stack;
InterfaceInfo *interface;
MethodInfo *method;
SignalInfo *signal;
ArgInfo *arg;
};
Parser*
parser_new (void)
{
Parser *parser;
parser = g_new0 (Parser, 1);
parser->refcount = 1;
return parser;
}
void
parser_ref (Parser *parser)
{
parser->refcount += 1;
}
void
parser_unref (Parser *parser)
{
parser->refcount -= 1;
if (parser->refcount == 0)
{
if (parser->result)
node_info_unref (parser->result);
g_free (parser);
}
}
gboolean
parser_check_doctype (Parser *parser,
const char *doctype,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (strcmp (doctype, "dbus_description") != 0)
{
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
"D-BUS description file has the wrong document type %s, use dbus_description",
doctype);
return FALSE;
}
else
return TRUE;
}
static gboolean
parse_node (Parser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error)
{
const char *name;
NodeInfo *node;
if (parser->interface ||
parser->method ||
parser->signal ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Can't put a <%s> element here"),
element_name);
return FALSE;
}
name = NULL;
if (!locate_attributes (element_name, attribute_names,
attribute_values, error,
"name", &name,
NULL))
return FALSE;
/* Only the root node can have no name */
if (parser->node_stack != NULL && name == NULL)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("\"%s\" attribute required on <%s> element "),
"name", element_name);
return FALSE;
}
node = node_info_new (name);
if (parser->node_stack != NULL)
{
node_info_add_node (parser->node_stack->data,
node);
}
parser->node_stack = g_slist_prepend (parser->node_stack,
node);
return TRUE;
}
static gboolean
parse_interface (Parser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error)
{
const char *name;
InterfaceInfo *iface;
NodeInfo *top;
if (parser->interface ||
parser->method ||
parser->signal ||
parser->arg ||
(parser->node_stack == NULL))
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Can't put a <%s> element here"),
element_name);
return FALSE;
}
name = NULL;
if (!locate_attributes (element_name, attribute_names,
attribute_values, error,
"name", &name,
NULL))
return FALSE;
if (name == NULL)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("\"%s\" attribute required on <%s> element "),
"name", element_name);
return FALSE;
}
top = parser->node_stack->data;
iface = interface_info_new (name);
node_info_add_interface (top, iface);
interface_info_unref (iface);
parser->interface = iface;
return TRUE;
}
static gboolean
parse_method (Parser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error)
{
const char *name;
MethodInfo *method;
NodeInfo *top;
if (parser->interface == NULL ||
parser->node_stack == NULL ||
parser->method ||
parser->signal ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Can't put a <%s> element here"),
element_name);
return FALSE;
}
name = NULL;
if (!locate_attributes (element_name, attribute_names,
attribute_values, error,
"name", &name,
NULL))
return FALSE;
if (name == NULL)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("\"%s\" attribute required on <%s> element "),
"name", element_name);
return FALSE;
}
top = parser->node_stack->data;
method = method_info_new (name);
interface_info_add_method (parser->interface, method);
method_info_unref (method);
parser->method = method;
return TRUE;
}
static gboolean
parse_signal (Parser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error)
{
const char *name;
SignalInfo *signal;
NodeInfo *top;
if (parser->interface == NULL ||
parser->node_stack == NULL ||
parser->signal ||
parser->signal ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Can't put a <%s> element here"),
element_name);
return FALSE;
}
name = NULL;
if (!locate_attributes (element_name, attribute_names,
attribute_values, error,
"name", &name,
NULL))
return FALSE;
if (name == NULL)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("\"%s\" attribute required on <%s> element "),
"name", element_name);
return FALSE;
}
top = parser->node_stack->data;
signal = signal_info_new (name);
interface_info_add_signal (parser->interface, signal);
signal_info_unref (signal);
parser->signal = signal;
return TRUE;
}
static int
basic_type_from_string (const char *str)
{
if (strcmp (str, "string") == 0)
return DBUS_TYPE_STRING;
else if (strcmp (str, "int32") == 0)
return DBUS_TYPE_INT32;
else if (strcmp (str, "uint32") == 0)
return DBUS_TYPE_UINT32;
else if (strcmp (str, "int64") == 0)
return DBUS_TYPE_INT64;
else if (strcmp (str, "uint64") == 0)
return DBUS_TYPE_UINT64;
else if (strcmp (str, "double") == 0)
return DBUS_TYPE_DOUBLE;
else if (strcmp (str, "byte") == 0)
return DBUS_TYPE_BYTE;
else if (strcmp (str, "boolean") == 0)
return DBUS_TYPE_BOOLEAN;
else if (strcmp (str, "byte") == 0)
return DBUS_TYPE_BYTE;
else if (strcmp (str, "object") == 0)
return DBUS_TYPE_OBJECT_PATH;
else
return DBUS_TYPE_INVALID;
}
static int
type_from_string (const char *str)
{
return basic_type_from_string (str);
}
static gboolean
parse_arg (Parser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error)
{
const char *name;
const char *type;
const char *direction;
ArgDirection dir;
int t;
ArgInfo *arg;
if (!(parser->method || parser->signal) ||
parser->node_stack == NULL ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Can't put a <%s> element here"),
element_name);
return FALSE;
}
name = NULL;
if (!locate_attributes (element_name, attribute_names,
attribute_values, error,
"name", &name,
"type", &type,
"direction", &direction,
NULL))
return FALSE;
/* name can be null for args */
if (type == NULL)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("\"%s\" attribute required on <%s> element "),
"type", element_name);
return FALSE;
}
if (direction == NULL)
{
/* methods default to in, signal to out */
if (parser->method)
direction = "in";
else if (parser->signal)
direction = "out";
else
g_assert_not_reached ();
}
if (strcmp (direction, "in") == 0)
dir = ARG_IN;
else if (strcmp (direction, "out") == 0)
dir = ARG_OUT;
else
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
"direction", element_name);
return FALSE;
}
t = type_from_string (type);
arg = arg_info_new (name, dir, t);
if (parser->method)
method_info_add_arg (parser->method, arg);
else if (parser->signal)
signal_info_add_arg (parser->signal, arg);
else
g_assert_not_reached ();
arg_info_unref (arg);
parser->arg = arg;
return TRUE;
}
gboolean
parser_start_element (Parser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (ELEMENT_IS ("node"))
{
if (!parse_node (parser, element_name, attribute_names,
attribute_values, error))
return FALSE;
}
else if (ELEMENT_IS ("interface"))
{
if (!parse_interface (parser, element_name, attribute_names,
attribute_values, error))
return FALSE;
}
else if (ELEMENT_IS ("method"))
{
if (!parse_method (parser, element_name, attribute_names,
attribute_values, error))
return FALSE;
}
else if (ELEMENT_IS ("signal"))
{
if (!parse_signal (parser, element_name, attribute_names,
attribute_values, error))
return FALSE;
}
else if (ELEMENT_IS ("arg"))
{
if (!parse_arg (parser, element_name, attribute_names,
attribute_values, error))
return FALSE;
}
else
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
_("Element <%s> not recognized"),
element_name);
}
return TRUE;
}
gboolean
parser_end_element (Parser *parser,
const char *element_name,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (ELEMENT_IS ("interface"))
{
parser->interface = NULL;
}
else if (ELEMENT_IS ("method"))
{
parser->method = NULL;
}
else if (ELEMENT_IS ("signal"))
{
parser->signal = NULL;
}
else if (ELEMENT_IS ("arg"))
{
parser->arg = NULL;
}
else if (ELEMENT_IS ("node"))
{
NodeInfo *top;
g_assert (parser->node_stack != NULL);
top = parser->node_stack->data;
parser->node_stack = g_slist_remove (parser->node_stack,
top);
if (parser->node_stack == NULL)
parser->result = top; /* We are done, store the result */
}
else
g_assert_not_reached (); /* should have had an error on start_element */
return TRUE;
}
gboolean
parser_content (Parser *parser,
const char *content,
int len,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
return TRUE;
}
gboolean
parser_finished (Parser *parser,
GError **error)
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
return TRUE;
}
NodeInfo*
parser_get_nodes (Parser *parser)
{
return parser->result;
}
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

65
glib/dbus-gparser.h Normal file
View file

@ -0,0 +1,65 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gparser.h parse DBus description files
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_GLIB_PARSER_H
#define DBUS_GLIB_PARSER_H
#include <dbus/dbus.h>
#include <glib.h>
#include "dbus-gidl.h"
G_BEGIN_DECLS
typedef struct Parser Parser;
Parser* parser_new (void);
void parser_ref (Parser *parser);
void parser_unref (Parser *parser);
gboolean parser_check_doctype (Parser *parser,
const char *doctype,
GError **error);
gboolean parser_start_element (Parser *parser,
const char *element_name,
const char **attribute_names,
const char **attribute_values,
GError **error);
gboolean parser_end_element (Parser *parser,
const char *element_name,
GError **error);
gboolean parser_content (Parser *parser,
const char *content,
int len,
GError **error);
gboolean parser_finished (Parser *parser,
GError **error);
NodeInfo* description_load_from_file (const char *filename,
GError **error);
NodeInfo* description_load_from_string (const char *str,
int len,
GError **error);
NodeInfo* parser_get_nodes (Parser *parser);
G_END_DECLS
#endif /* DBUS_GLIB_GPARSER_H */

1249
glib/dbus-gproxy.c Normal file

File diff suppressed because it is too large Load diff

46
glib/dbus-gtest-main.c Normal file
View file

@ -0,0 +1,46 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gtest-main.c Program to run all libdbus-glib tests
*
* Copyright (C) 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "dbus-gtest.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int
main (int argc,
char **argv)
{
const char *test_data_dir;
setlocale(LC_ALL, "");
if (argc > 1)
test_data_dir = argv[1];
else
test_data_dir = NULL;
dbus_glib_internal_do_not_use_run_tests (test_data_dir);
return 0;
}

77
glib/dbus-gtest.c Normal file
View file

@ -0,0 +1,77 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-test.c Program to run all tests
*
* Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include "dbus-gtest.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef DBUS_BUILD_TESTS
static void
die (const char *failure)
{
fprintf (stderr, "Unit test failed: %s\n", failure);
exit (1);
}
#endif /* DBUS_BUILD_TESTS */
/**
* An exported symbol to be run in order to execute
* unit tests. Should not be used by
* any app other than our test app, this symbol
* won't exist in some builds of the library.
* (with --enable-tests=no)
*
* @param test_data_dir the directory with test data (test/data normally)
*/
void
dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir)
{
#ifdef DBUS_BUILD_TESTS
if (test_data_dir == NULL)
test_data_dir = g_getenv ("DBUS_TEST_DATA");
if (test_data_dir != NULL)
printf ("Test data in %s\n", test_data_dir);
else
printf ("No test data!\n");
printf ("%s: running utils tests\n", "dbus-glib-test");
if (!_dbus_gutils_test (test_data_dir))
die ("gutils");
printf ("%s: running mainloop integration tests\n", "dbus-glib-test");
if (!_dbus_gmain_test (test_data_dir))
die ("gmain");
printf ("%s: running GObject tests\n", "dbus-glib-test");
if (!_dbus_gobject_test (test_data_dir))
die ("gobject");
printf ("%s: completed successfully\n", "dbus-glib-test");
#else
printf ("Not compiled with unit tests, not running any\n");
#endif
}

35
glib/dbus-gtest.h Normal file
View file

@ -0,0 +1,35 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gtest.h Declarations of test functions.
*
* Copyright (C) 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_GLIB_TEST_H
#define DBUS_GLIB_TEST_H
#include "dbus-glib.h"
dbus_bool_t _dbus_gmain_test (const char *test_data_dir);
dbus_bool_t _dbus_gobject_test (const char *test_data_dir);
dbus_bool_t _dbus_gutils_test (const char *test_data_dir);
void dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir);
#endif /* DBUS_GLIB_TEST_H */

View file

@ -165,7 +165,7 @@ dbus_gcondvar_wake_all (DBusCondVar *cond)
* other function in the D-BUS API.
*/
void
dbus_gthread_init (void)
dbus_g_thread_init (void)
{
if (!g_thread_supported ())
g_error ("g_thread_init() must be called before dbus_threads_init()");

31
glib/dbus-gtool-test.h Normal file
View file

@ -0,0 +1,31 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gtool-test.h Declarations of test functions for dbus-glib-tool.
*
* Copyright (C) 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_GLIB_TOOL_TEST_H
#define DBUS_GLIB_TOOL_TEST_H
#include "dbus-glib.h"
dbus_bool_t _dbus_gtool_test (const char *test_data_dir);
#endif /* DBUS_GLIB_TEST_H */

96
glib/dbus-gutils.c Normal file
View file

@ -0,0 +1,96 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gutils.c Utils shared between convenience lib and installed lib
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include "dbus-gutils.h"
#include "dbus-gtest.h"
#include <string.h>
#ifndef DOXYGEN_SHOULD_SKIP_THIS
char**
_dbus_gutils_split_path (const char *path)
{
int len;
char **split;
int n_components;
int i, j, comp;
len = strlen (path);
n_components = 0;
i = 0;
while (i < len)
{
if (path[i] == '/')
n_components += 1;
++i;
}
split = g_new0 (char*, n_components + 1);
comp = 0;
i = 0;
while (i < len)
{
if (path[i] == '/')
++i;
j = i;
while (j < len && path[j] != '/')
++j;
/* Now [i, j) is the path component */
g_assert (i < j);
g_assert (path[i] != '/');
g_assert (j == len || path[j] == '/');
split[comp] = g_strndup (&path[i], j - i + 1);
split[comp][j-i] = '\0';
++comp;
i = j;
}
g_assert (i == len);
return split;
}
#ifdef DBUS_BUILD_TESTS
/**
* @ingroup DBusGLibInternals
* Unit test for GLib utils internals
* @returns #TRUE on success.
*/
dbus_bool_t
_dbus_gutils_test (const char *test_data_dir)
{
return TRUE;
}
#endif /* DBUS_BUILD_TESTS */
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

40
glib/dbus-gutils.h Normal file
View file

@ -0,0 +1,40 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gutils.h Utils shared between convenience lib and installed lib
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef DBUS_GLIB_UTILS_H
#define DBUS_GLIB_UTILS_H
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <dbus/dbus.h>
#include <glib-object.h>
G_BEGIN_DECLS
char** _dbus_gutils_split_path (const char *path);
G_END_DECLS
#endif /* DBUS_GLIB_UTILS_H */
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

View file

@ -1,6 +1,13 @@
if HAVE_GLIB
GLIB_SUBDIR=glib
endif
SUBDIRS=$(GLIB_SUBDIR)
INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS)
if DBUS_BUILD_TESTS
TEST_BINARIES=test-service unbase64 break-loader spawn-test test-segfault test-exit test-sleep-forever
else
@ -82,7 +89,7 @@ all-local:
for D in $(TESTDIRS); do \
test -d $(top_builddir)/test/$$D || mkdir $(top_builddir)/test/$$D || exit 1 ; \
done ; \
if test $(srcdir) != . ; then \
if ! (test $(srcdir) = . || test $(srcdir) -ef .) ; then \
FILES=`(cd $(srcdir) && $(FIND_TESTS))` ; \
for F in $$FILES; do \
SRC=$(srcdir)/$$F ; \

Some files were not shown because too many files have changed in this diff Show more