mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2025-12-25 12:50:07 +01:00
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:
commit
dfd1292d52
145 changed files with 15672 additions and 3073 deletions
|
|
@ -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
|
||||
|
|
|
|||
9
HACKING
9
HACKING
|
|
@ -90,11 +90,12 @@ To make a release of D-BUS, do the following:
|
|||
- once the commit succeeds, "cvs tag DBUS_X_Y_Z" where
|
||||
X_Y_Z map to version X.Y.Z
|
||||
|
||||
- check out the "web" module, copy the tarball to
|
||||
web/content/software/dbus/releases, "cvs add -kb dbus-x.y.z.tar.gz"
|
||||
- scp your tarball to freedesktop.org server and copy it
|
||||
to /home/www/twiki/Software/dbus/releases. This should
|
||||
be possible if you're in group "dbus"
|
||||
|
||||
- update web/content/software/dbus/main.in with a pointer to the
|
||||
tarball
|
||||
- update the wiki page http://pdx.freedesktop.org/Software/dbus
|
||||
to list your new release
|
||||
|
||||
- post to message-bus-list@freedesktop.org announcing the release.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
26
acinclude.m4
26
acinclude.m4
|
|
@ -55,3 +55,29 @@ AC_DEFUN(PKG_CHECK_MODULES, [
|
|||
])
|
||||
|
||||
|
||||
|
||||
dnl a macro to check for ability to create python extensions
|
||||
dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
|
||||
dnl function also defines PYTHON_INCLUDES
|
||||
AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
|
||||
[AC_REQUIRE([AM_PATH_PYTHON])
|
||||
AC_MSG_CHECKING(for headers required to compile python extensions)
|
||||
dnl deduce PYTHON_INCLUDES
|
||||
py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
|
||||
py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
|
||||
PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
|
||||
if test "$py_prefix" != "$py_exec_prefix"; then
|
||||
PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
|
||||
fi
|
||||
AC_SUBST(PYTHON_INCLUDES)
|
||||
dnl check if the headers exist:
|
||||
save_CPPFLAGS="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
|
||||
AC_TRY_CPP([#include <Python.h>],dnl
|
||||
[AC_MSG_RESULT(found)
|
||||
$1],dnl
|
||||
[AC_MSG_RESULT(not found)
|
||||
$2])
|
||||
CPPFLAGS="$save_CPPFLAGS"
|
||||
])
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ BUS_SOURCES= \
|
|||
policy.h \
|
||||
services.c \
|
||||
services.h \
|
||||
signals.c \
|
||||
signals.h \
|
||||
test.c \
|
||||
test.h \
|
||||
utils.c \
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ bus_activation_service_created (BusActivation *activation,
|
|||
|
||||
if (dbus_connection_get_is_connected (entry->connection))
|
||||
{
|
||||
message = dbus_message_new_reply (entry->activation_message);
|
||||
message = dbus_message_new_method_return (entry->activation_message);
|
||||
if (!message)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
|
|
@ -866,7 +866,7 @@ bus_activation_activate_service (BusActivation *activation,
|
|||
{
|
||||
_dbus_verbose ("Service \"%s\" is already active\n", service_name);
|
||||
|
||||
message = dbus_message_new_reply (activation_message);
|
||||
message = dbus_message_new_method_return (activation_message);
|
||||
|
||||
if (!message)
|
||||
{
|
||||
|
|
|
|||
97
bus/bus.c
97
bus/bus.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
71
bus/bus.h
71
bus/bus.h
|
|
@ -40,7 +40,8 @@ typedef struct BusPolicyRule BusPolicyRule;
|
|||
typedef struct BusRegistry BusRegistry;
|
||||
typedef struct BusService BusService;
|
||||
typedef struct BusTransaction BusTransaction;
|
||||
|
||||
typedef struct BusMatchmaker BusMatchmaker;
|
||||
typedef struct BusMatchRule BusMatchRule;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -54,40 +55,44 @@ typedef struct
|
|||
int max_connections_per_user; /**< Max number of connections auth'd as same user */
|
||||
int max_pending_activations; /**< Max number of pending activations for the entire bus */
|
||||
int max_services_per_connection; /**< Max number of owned services for a single connection */
|
||||
int max_match_rules_per_connection; /**< Max number of match rules for a single connection */
|
||||
} BusLimits;
|
||||
|
||||
BusContext* bus_context_new (const DBusString *config_file,
|
||||
dbus_bool_t force_fork,
|
||||
int print_addr_fd,
|
||||
int print_pid_fd,
|
||||
DBusError *error);
|
||||
void bus_context_shutdown (BusContext *context);
|
||||
void bus_context_ref (BusContext *context);
|
||||
void bus_context_unref (BusContext *context);
|
||||
const char* bus_context_get_type (BusContext *context);
|
||||
const char* bus_context_get_address (BusContext *context);
|
||||
BusRegistry* bus_context_get_registry (BusContext *context);
|
||||
BusConnections* bus_context_get_connections (BusContext *context);
|
||||
BusActivation* bus_context_get_activation (BusContext *context);
|
||||
DBusLoop* bus_context_get_loop (BusContext *context);
|
||||
DBusUserDatabase* bus_context_get_user_database (BusContext *context);
|
||||
dbus_bool_t bus_context_allow_user (BusContext *context,
|
||||
unsigned long uid);
|
||||
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
|
||||
DBusConnection *connection,
|
||||
DBusError *error);
|
||||
BusContext* bus_context_new (const DBusString *config_file,
|
||||
dbus_bool_t force_fork,
|
||||
int print_addr_fd,
|
||||
int print_pid_fd,
|
||||
DBusError *error);
|
||||
void bus_context_shutdown (BusContext *context);
|
||||
void bus_context_ref (BusContext *context);
|
||||
void bus_context_unref (BusContext *context);
|
||||
const char* bus_context_get_type (BusContext *context);
|
||||
const char* bus_context_get_address (BusContext *context);
|
||||
BusRegistry* bus_context_get_registry (BusContext *context);
|
||||
BusConnections* bus_context_get_connections (BusContext *context);
|
||||
BusActivation* bus_context_get_activation (BusContext *context);
|
||||
BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
|
||||
DBusLoop* bus_context_get_loop (BusContext *context);
|
||||
DBusUserDatabase* bus_context_get_user_database (BusContext *context);
|
||||
dbus_bool_t bus_context_allow_user (BusContext *context,
|
||||
unsigned long uid);
|
||||
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
|
||||
DBusConnection *connection,
|
||||
DBusError *error);
|
||||
int bus_context_get_activation_timeout (BusContext *context);
|
||||
int bus_context_get_auth_timeout (BusContext *context);
|
||||
int bus_context_get_max_completed_connections (BusContext *context);
|
||||
int bus_context_get_max_incomplete_connections (BusContext *context);
|
||||
int bus_context_get_max_connections_per_user (BusContext *context);
|
||||
int bus_context_get_max_pending_activations (BusContext *context);
|
||||
int bus_context_get_max_services_per_connection (BusContext *context);
|
||||
int bus_context_get_max_match_rules_per_connection (BusContext *context);
|
||||
dbus_bool_t bus_context_check_security_policy (BusContext *context,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *addressed_recipient,
|
||||
DBusConnection *proposed_recipient,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
|
||||
int bus_context_get_activation_timeout (BusContext *context);
|
||||
int bus_context_get_auth_timeout (BusContext *context);
|
||||
int bus_context_get_max_completed_connections (BusContext *context);
|
||||
int bus_context_get_max_incomplete_connections (BusContext *context);
|
||||
int bus_context_get_max_connections_per_user (BusContext *context);
|
||||
int bus_context_get_max_pending_activations (BusContext *context);
|
||||
int bus_context_get_max_services_per_connection (BusContext *context);
|
||||
dbus_bool_t bus_context_check_security_policy (BusContext *context,
|
||||
DBusConnection *sender,
|
||||
DBusConnection *recipient,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
|
||||
#endif /* BUS_BUS_H */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
169
bus/connection.c
169
bus/connection.c
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
649
bus/dispatch.c
649
bus/dispatch.c
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
252
bus/driver.c
252
bus/driver.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
178
bus/policy.c
178
bus/policy.c
|
|
@ -52,7 +52,11 @@ bus_policy_rule_new (BusPolicyRuleType type,
|
|||
rule->d.group.gid = DBUS_GID_UNSET;
|
||||
break;
|
||||
case BUS_POLICY_RULE_SEND:
|
||||
rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
|
||||
break;
|
||||
case BUS_POLICY_RULE_RECEIVE:
|
||||
rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
|
||||
break;
|
||||
case BUS_POLICY_RULE_OWN:
|
||||
break;
|
||||
}
|
||||
|
|
@ -80,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;
|
||||
|
||||
|
|
|
|||
21
bus/policy.h
21
bus/policy.h
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
778
bus/signals.c
Normal 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
83
bus/signals.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
61
bus/test.c
61
bus/test.c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
81
configure.in
81
configure.in
|
|
@ -24,6 +24,7 @@ AC_HEADER_STDC
|
|||
|
||||
AC_ARG_ENABLE(qt, [ --enable-qt enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto)
|
||||
AC_ARG_ENABLE(glib, [ --enable-glib enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto)
|
||||
AC_ARG_ENABLE(gtk, [ --enable-gtk enable GTK-requiring executables],enable_gtk=$enableval,enable_gtk=auto)
|
||||
AC_ARG_ENABLE(tests, [ --enable-tests enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE)
|
||||
AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
|
||||
AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
159
dbus/dbus-bus.c
159
dbus/dbus-bus.c
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbus-bus.h"
|
||||
#include "dbus-protocol.h"
|
||||
#include "dbus-internals.h"
|
||||
#include "dbus-message.h"
|
||||
#include <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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
410
dbus/dbus-hash.c
410
dbus/dbus-hash.c
|
|
@ -221,26 +221,32 @@ typedef struct
|
|||
int n_entries_on_init; /**< used to detect table resize since initialization */
|
||||
} DBusRealHashIter;
|
||||
|
||||
static DBusHashEntry* find_direct_function (DBusHashTable *table,
|
||||
void *key,
|
||||
dbus_bool_t create_if_not_found,
|
||||
DBusHashEntry ***bucket,
|
||||
DBusPreallocatedHash *preallocated);
|
||||
static DBusHashEntry* find_string_function (DBusHashTable *table,
|
||||
void *key,
|
||||
dbus_bool_t create_if_not_found,
|
||||
DBusHashEntry ***bucket,
|
||||
DBusPreallocatedHash *preallocated);
|
||||
static unsigned int string_hash (const char *str);
|
||||
static void rebuild_table (DBusHashTable *table);
|
||||
static DBusHashEntry* alloc_entry (DBusHashTable *table);
|
||||
static void remove_entry (DBusHashTable *table,
|
||||
DBusHashEntry **bucket,
|
||||
DBusHashEntry *entry);
|
||||
static void free_entry (DBusHashTable *table,
|
||||
DBusHashEntry *entry);
|
||||
static void free_entry_data (DBusHashTable *table,
|
||||
DBusHashEntry *entry);
|
||||
static DBusHashEntry* find_direct_function (DBusHashTable *table,
|
||||
void *key,
|
||||
dbus_bool_t create_if_not_found,
|
||||
DBusHashEntry ***bucket,
|
||||
DBusPreallocatedHash *preallocated);
|
||||
static DBusHashEntry* find_string_function (DBusHashTable *table,
|
||||
void *key,
|
||||
dbus_bool_t create_if_not_found,
|
||||
DBusHashEntry ***bucket,
|
||||
DBusPreallocatedHash *preallocated);
|
||||
static DBusHashEntry* find_two_strings_function (DBusHashTable *table,
|
||||
void *key,
|
||||
dbus_bool_t create_if_not_found,
|
||||
DBusHashEntry ***bucket,
|
||||
DBusPreallocatedHash *preallocated);
|
||||
static unsigned int string_hash (const char *str);
|
||||
static unsigned int two_strings_hash (const char *str);
|
||||
static void rebuild_table (DBusHashTable *table);
|
||||
static DBusHashEntry* alloc_entry (DBusHashTable *table);
|
||||
static void remove_entry (DBusHashTable *table,
|
||||
DBusHashEntry **bucket,
|
||||
DBusHashEntry *entry);
|
||||
static void free_entry (DBusHashTable *table,
|
||||
DBusHashEntry *entry);
|
||||
static void free_entry_data (DBusHashTable *table,
|
||||
DBusHashEntry *entry);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
|
@ -323,6 +329,9 @@ _dbus_hash_table_new (DBusHashType type,
|
|||
case DBUS_HASH_STRING:
|
||||
table->find_function = find_string_function;
|
||||
break;
|
||||
case DBUS_HASH_TWO_STRINGS:
|
||||
table->find_function = find_two_strings_function;
|
||||
break;
|
||||
default:
|
||||
_dbus_assert_not_reached ("Unknown hash table type");
|
||||
break;
|
||||
|
|
@ -684,6 +693,24 @@ _dbus_hash_iter_get_string_key (DBusHashIter *iter)
|
|||
return real->entry->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key for the current entry.
|
||||
* Only works for hash tables of type #DBUS_HASH_TWO_STRINGS
|
||||
* @param iter the hash table iterator.
|
||||
*/
|
||||
const char*
|
||||
_dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)
|
||||
{
|
||||
DBusRealHashIter *real;
|
||||
|
||||
real = (DBusRealHashIter*) iter;
|
||||
|
||||
_dbus_assert (real->table != NULL);
|
||||
_dbus_assert (real->entry != NULL);
|
||||
|
||||
return real->entry->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* A low-level but efficient interface for manipulating the hash
|
||||
* table. It's efficient because you can get, set, and optionally
|
||||
|
|
@ -803,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
|
||||
|
|
|
|||
131
dbus/dbus-hash.h
131
dbus/dbus-hash.h
|
|
@ -29,17 +29,17 @@
|
|||
|
||||
DBUS_BEGIN_DECLS;
|
||||
|
||||
/* The iterator is on the stack, but its real fields are
|
||||
* hidden privately.
|
||||
/** Hash iterator object. The iterator is on the stack, but its real
|
||||
* fields are hidden privately.
|
||||
*/
|
||||
struct DBusHashIter
|
||||
{
|
||||
void *dummy1;
|
||||
void *dummy2;
|
||||
void *dummy3;
|
||||
void *dummy4;
|
||||
int dummy5;
|
||||
int dummy6;
|
||||
void *dummy1; /**< Do not use. */
|
||||
void *dummy2; /**< Do not use. */
|
||||
void *dummy3; /**< Do not use. */
|
||||
void *dummy4; /**< Do not use. */
|
||||
int dummy5; /**< Do not use. */
|
||||
int dummy6; /**< Do not use. */
|
||||
};
|
||||
|
||||
typedef struct DBusHashTable DBusHashTable;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
1669
dbus/dbus-message.c
1669
dbus/dbus-message.c
File diff suppressed because it is too large
Load diff
|
|
@ -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
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
52
dbus/dbus-object-tree.h
Normal 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
429
dbus/dbus-pending-call.c
Normal 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 (¬ify_user_data_slot))
|
||||
return NULL;
|
||||
|
||||
pending = dbus_new (DBusPendingCall, 1);
|
||||
|
||||
if (pending == NULL)
|
||||
{
|
||||
dbus_pending_call_free_data_slot (¬ify_user_data_slot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timeout = _dbus_timeout_new (timeout_milliseconds,
|
||||
timeout_handler,
|
||||
pending, NULL);
|
||||
|
||||
if (timeout == NULL)
|
||||
{
|
||||
dbus_pending_call_free_data_slot (¬ify_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 (¬ify_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
58
dbus/dbus-pending-call.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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() */
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internals of DBusTimeout
|
||||
*/
|
||||
struct DBusTimeout
|
||||
{
|
||||
int refcount; /**< Reference count */
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of DBusWatch
|
||||
*/
|
||||
struct DBusWatch
|
||||
{
|
||||
int refcount; /**< Reference count */
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
30
doc/TODO
30
doc/TODO
|
|
@ -23,9 +23,6 @@
|
|||
(changing get_string to have an error return, and allowing a type error
|
||||
as a possible return)
|
||||
|
||||
- We might consider returning a "no such operation" error in dbus-connection.c
|
||||
for unhandled messages.
|
||||
|
||||
- The convenience functions in dbus-bus.h should perhaps have
|
||||
the signatures that they would have if they were autogenerated
|
||||
stubs. e.g. the acquire service function. We should also evaluate
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
524
glib/dbus-gidl.c
Normal 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
120
glib/dbus-gidl.h
Normal 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
77
glib/dbus-glib-tool.c
Normal 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 */
|
||||
121
glib/dbus-glib.h
121
glib/dbus-glib.h
|
|
@ -2,6 +2,7 @@
|
|||
/* dbus-glib.h GLib integration
|
||||
*
|
||||
* Copyright (C) 2002, 2003 CodeFactory AB
|
||||
* Copyright (C) 2003 Red Hat, Inc.
|
||||
*
|
||||
* Licensed under the Academic Free License version 1.2
|
||||
*
|
||||
|
|
@ -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
262
glib/dbus-gloader-expat.c
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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
790
glib/dbus-gobject.c
Normal 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
670
glib/dbus-gparser.c
Normal 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
65
glib/dbus-gparser.h
Normal 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
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
46
glib/dbus-gtest-main.c
Normal 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
77
glib/dbus-gtest.c
Normal 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
35
glib/dbus-gtest.h
Normal 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 */
|
||||
|
|
@ -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
31
glib/dbus-gtool-test.h
Normal 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
96
glib/dbus-gutils.c
Normal 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
40
glib/dbus-gutils.h
Normal 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 */
|
||||
|
|
@ -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
Loading…
Add table
Reference in a new issue