From 853e7f19df8ce206939343bb086d6e0de8f23f3c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 18 Mar 2009 18:25:28 -0400 Subject: [PATCH] Bug 896 - Implement org.freedesktop.DBus.Peer for the bus We want the bus to reply to the Peer interface for obvious reasons. To implement, refactor the code in dbus-connection so that we have a (internal public) method to process a message and create the reply. The actual sending function differs from bus-internal versus from a DBusConnection, so we can't just call the peer filter directly. Create a test too. --- bus/driver.c | 81 ++++++++++++++----- dbus/dbus-connection-internal.h | 4 + dbus/dbus-connection.c | 167 ++++++++++++++++++++------------------ test/name-test/Makefile.am | 10 ++- test/name-test/run-test.sh | 3 + test/name-test/test-bus-peer.c | 59 ++++++++++++++ 6 files changed, 223 insertions(+), 101 deletions(-) create mode 100644 test/name-test/test-bus-peer.c diff --git a/bus/driver.c b/bus/driver.c index c97bff5..ffce47f 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -33,6 +33,7 @@ #include #include #include +#include #include static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection, @@ -1914,6 +1915,43 @@ bus_driver_handle_introspect (DBusConnection *connection, return FALSE; } +static dbus_bool_t +bus_driver_handle_peer (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + + reply = NULL; + if (!_dbus_connection_create_peer_response (connection, message, &reply)) + goto oom; + + if (reply == NULL) + { + dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD, + "%s does not understand message %s", + DBUS_SERVICE_DBUS, + dbus_message_get_member (message)); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + if (reply) + dbus_message_unref (reply); + + return FALSE; +} + dbus_bool_t bus_driver_handle_message (DBusConnection *connection, BusTransaction *transaction, @@ -1931,33 +1969,34 @@ bus_driver_handle_message (DBusConnection *connection, return TRUE; /* we just ignore this */ } - if (dbus_message_is_method_call (message, - DBUS_INTERFACE_INTROSPECTABLE, - "Introspect")) - return bus_driver_handle_introspect (connection, transaction, message, error); - + name = dbus_message_get_member (message); + sender = dbus_message_get_sender (message); interface = dbus_message_get_interface (message); - if (interface == NULL) - interface = DBUS_INTERFACE_DBUS; - + _dbus_assert (dbus_message_get_member (message) != NULL); + /* security checks should have kept this from getting here */ + _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0); - name = dbus_message_get_member (message); - sender = dbus_message_get_sender (message); + _dbus_verbose ("Driver got a method call: %s\n", + dbus_message_get_member (message)); - if (strcmp (interface, - DBUS_INTERFACE_DBUS) != 0) + if (interface != NULL) { - _dbus_verbose ("Driver got message to unknown interface \"%s\"\n", - interface); - goto unknown; + if (dbus_message_is_method_call (message, + DBUS_INTERFACE_INTROSPECTABLE, + "Introspect")) + return bus_driver_handle_introspect (connection, transaction, message, error); + else if (strcmp (interface, DBUS_INTERFACE_PEER) == 0) + return bus_driver_handle_peer (connection, transaction, message, error); + else if (strcmp (interface, DBUS_INTERFACE_DBUS) != 0) + { + _dbus_verbose ("Driver got message to unknown interface \"%s\"\n", + interface); + 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, "Hello") == 0); + else + interface = DBUS_INTERFACE_DBUS; i = 0; while (i < _DBUS_N_ELEMENTS (message_handlers)) diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index df54412..b7e4840 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -80,6 +80,10 @@ void _dbus_connection_do_iteration_unlocked (DBusConnection void _dbus_connection_close_possibly_shared (DBusConnection *connection); void _dbus_connection_close_if_only_one_ref (DBusConnection *connection); +dbus_bool_t _dbus_connection_create_peer_response (DBusConnection *connection, + DBusMessage *message, + DBusMessage **response); + DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, int timeout_milliseconds, DBusTimeoutHandler timeout_handler); diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ae07adf..80082c8 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -4119,99 +4119,108 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) } /** - * Filter funtion for handling the Peer standard interface. + * Process a message sent to the standard org.freedesktop.DBus.Peer + * interface. This function has 2 return values, and 3 valid + * cases of those values. + * + * #TRUE return, non-#NULL response: Valid message, handled successfully + * #TRUE return, #NULL response: Invalid message, handled successfully + * #FALSE return: Out of memory (response will be #NULL) + * + * Note this function is shared between the normal #DBusConnection case, + * and the bus driver. + */ +dbus_bool_t +_dbus_connection_create_peer_response (DBusConnection *connection, + DBusMessage *message, + DBusMessage **response) +{ + *response = NULL; + + if (dbus_message_is_method_call (message, + DBUS_INTERFACE_PEER, + "Ping")) + { + dbus_bool_t sent; + + *response = dbus_message_new_method_return (message); + if (*response == NULL) + return FALSE; + return TRUE; + } + else if (dbus_message_is_method_call (message, + DBUS_INTERFACE_PEER, + "GetMachineId")) + { + DBusMessage *ret; + DBusString uuid; + dbus_bool_t retval; + + retval = FALSE; + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + return FALSE; + + _dbus_string_init (&uuid); + if (_dbus_get_local_machine_uuid_encoded (&uuid)) + { + const char *v_STRING = _dbus_string_get_const_data (&uuid); + retval = dbus_message_append_args (ret, + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_INVALID); + } + _dbus_string_free (&uuid); + + if (retval) + *response = ret; + + return retval; + } + + /* TRUE return, NULL response means "unhandled message" */ + return TRUE; +} + +/** + * Filter function for handling the Peer standard interface. */ static DBusHandlerResult _dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection, DBusMessage *message) { + DBusMessage *reply; + dbus_bool_t sent; + + if (!dbus_message_has_interface (message, DBUS_INTERFACE_PEER)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (connection->route_peer_messages && dbus_message_get_destination (message) != NULL) { /* This means we're letting the bus route this message */ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - else if (dbus_message_is_method_call (message, - DBUS_INTERFACE_PEER, - "Ping")) - { - DBusMessage *ret; - dbus_bool_t sent; - - ret = dbus_message_new_method_return (message); - if (ret == NULL) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); - dbus_message_unref (ret); + if (!_dbus_connection_create_peer_response (connection, message, &reply)) + return DBUS_HANDLER_RESULT_NEED_MEMORY; - if (!sent) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - return DBUS_HANDLER_RESULT_HANDLED; - } - else if (dbus_message_is_method_call (message, - DBUS_INTERFACE_PEER, - "GetMachineId")) - { - DBusMessage *ret; - dbus_bool_t sent; - DBusString uuid; - - ret = dbus_message_new_method_return (message); - if (ret == NULL) - return DBUS_HANDLER_RESULT_NEED_MEMORY; + if (reply == NULL) + /* We need to bounce anything else with this interface, otherwise apps + * could start extending the interface and when we added extensions + * here to DBusConnection we'd break those apps. + */ + reply = dbus_message_new_error (message, + DBUS_ERROR_UNKNOWN_METHOD, + "Unknown method invoked on org.freedesktop.DBus.Peer interface"); - sent = FALSE; - _dbus_string_init (&uuid); - if (_dbus_get_local_machine_uuid_encoded (&uuid)) - { - const char *v_STRING = _dbus_string_get_const_data (&uuid); - if (dbus_message_append_args (ret, - DBUS_TYPE_STRING, &v_STRING, - DBUS_TYPE_INVALID)) - { - sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); - } - } - _dbus_string_free (&uuid); - - dbus_message_unref (ret); + sent = _dbus_connection_send_unlocked_no_update (connection, reply, NULL); - if (!sent) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - return DBUS_HANDLER_RESULT_HANDLED; - } - else if (dbus_message_has_interface (message, DBUS_INTERFACE_PEER)) - { - /* We need to bounce anything else with this interface, otherwise apps - * could start extending the interface and when we added extensions - * here to DBusConnection we'd break those apps. - */ - - DBusMessage *ret; - dbus_bool_t sent; - - ret = dbus_message_new_error (message, - DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method invoked on org.freedesktop.DBus.Peer interface"); - if (ret == NULL) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); - - dbus_message_unref (ret); - - if (!sent) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - return DBUS_HANDLER_RESULT_HANDLED; - } - else - { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } + dbus_message_unref (reply); + + if (!sent) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return DBUS_HANDLER_RESULT_HANDLED; } /** diff --git a/test/name-test/Makefile.am b/test/name-test/Makefile.am index 10a2536..a0832a7 100644 --- a/test/name-test/Makefile.am +++ b/test/name-test/Makefile.am @@ -16,7 +16,9 @@ if DBUS_BUILD_TESTS ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we ## build even when not doing "make check" -noinst_PROGRAMS=test-names test-pending-call-dispatch test-threads-init test-ids test-shutdown test-privserver test-privserver-client +noinst_PROGRAMS=test-names test-pending-call-dispatch test-threads-init \ + test-ids test-bus-peer test-shutdown test-privserver \ + test-privserver-client test_names_SOURCES= \ test-names.c @@ -42,6 +44,12 @@ test_ids_SOURCES = \ test_ids_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) test_ids_LDFLAGS=@R_DYNAMIC_LDFLAG@ +test_bus_peer_SOURCES = \ + test-bus-peer.c + +test_bus_peer_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +test_bus_peer_LDFLAGS=@R_DYNAMIC_LDFLAG@ + test_shutdown_SOURCES = \ test-shutdown.c diff --git a/test/name-test/run-test.sh b/test/name-test/run-test.sh index 3699bc9..2f73868 100755 --- a/test/name-test/run-test.sh +++ b/test/name-test/run-test.sh @@ -33,6 +33,9 @@ fi echo "running test-ids" ${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-ids || die "test-ids failed" +echo "running test-bus-peer" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-bus-peer || die "test-bus-peer failed" + echo "running test-names" ${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-names || die "test-names failed" diff --git a/test/name-test/test-bus-peer.c b/test/name-test/test-bus-peer.c new file mode 100644 index 0000000..a0e0acb --- /dev/null +++ b/test/name-test/test-bus-peer.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +static void +die (const char *message) +{ + fprintf (stderr, "*** test-bus-peer: %s", message); + exit (1); +} + +int +main (int argc, + char **argv) +{ + DBusError error; + DBusConnection *connection; + DBusMessage *message; + DBusMessage *reply; + + dbus_error_init (&error); + connection = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (connection == NULL) + { + fprintf (stderr, "*** Failed to open connection to session bus: %s\n", + error.message); + dbus_error_free (&error); + return 1; + } + + /* The bus should implement org.freedesktop.DBus.Peer */ + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_PEER, + "Ping"); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (dbus_error_is_set (&error)) + die (error.message); + dbus_message_unref (reply); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_PEER, + "GetMachineId"); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (dbus_error_is_set (&error)) + die (error.message); + dbus_message_unref (reply); + + _dbus_verbose ("*** Test bus peer exiting\n"); + + return 0; +} -- 1.6.0.6