mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-05 03:10:15 +01:00
The o.fd.DBus interface needs to remain available on arbitrary object paths for backwards compatibility, and the Introspectable interface is genuinely useful, but everything else can be skipped. This is arguably an incompatible change for the undocumented Verbose interface, and for the GetAllMatchRules method on the undocumented Stats interface: previously those were available at all object paths. Reviewed-by: Philip Withnall <withnall@endlessm.com> [smcv: Adjust comments, enum order, variable naming as per Philip's review] Signed-off-by: Simon McVittie <smcv@collabora.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101256
1878 lines
56 KiB
C
1878 lines
56 KiB
C
/* Integration tests for monitor-mode D-Bus connections
|
|
*
|
|
* Copyright © 2010-2011 Nokia Corporation
|
|
* Copyright © 2015 Collabora Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation files
|
|
* (the "Software"), to deal in the Software without restriction,
|
|
* including without limitation the rights to use, copy, modify, merge,
|
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
* and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "test-utils-glib.h"
|
|
|
|
typedef struct {
|
|
const char *config_file;
|
|
const char * const *match_rules;
|
|
gboolean care_about_our_names;
|
|
} Config;
|
|
|
|
typedef struct {
|
|
const Config *config;
|
|
TestMainContext *ctx;
|
|
DBusError e;
|
|
GError *ge;
|
|
|
|
gchar *address;
|
|
GPid daemon_pid;
|
|
|
|
DBusConnection *monitor;
|
|
DBusConnection *sender;
|
|
DBusConnection *recipient;
|
|
|
|
GQueue monitored;
|
|
|
|
const char *monitor_name;
|
|
const char *sender_name;
|
|
const char *recipient_name;
|
|
|
|
DBusConnection *systemd;
|
|
const char *systemd_name;
|
|
DBusMessage *systemd_message;
|
|
DBusConnection *activated;
|
|
const char *activated_name;
|
|
DBusMessage *activated_message;
|
|
} Fixture;
|
|
|
|
static const char * const no_match_rules[] = {
|
|
NULL
|
|
};
|
|
|
|
static const char * const wildcard_match_rules[] = {
|
|
"",
|
|
NULL,
|
|
FALSE
|
|
};
|
|
|
|
static const char * const eavesdrop_match_rules[] = {
|
|
"eavesdrop=true",
|
|
NULL,
|
|
FALSE
|
|
};
|
|
|
|
static const char * const no_eavesdrop_match_rules[] = {
|
|
"eavesdrop=false",
|
|
NULL,
|
|
FALSE
|
|
};
|
|
|
|
static const char * const selective_match_rules[] = {
|
|
"interface='com.example.Interesting'",
|
|
"interface='com.example.Fun'",
|
|
NULL,
|
|
FALSE
|
|
};
|
|
|
|
static const char * const well_known_destination_match_rules[] = {
|
|
"destination='com.example.Recipient'",
|
|
NULL
|
|
};
|
|
|
|
static Config forbidding_config = {
|
|
"valid-config-files/forbidding.conf",
|
|
NULL,
|
|
FALSE
|
|
};
|
|
|
|
static Config wildcard_config = {
|
|
NULL,
|
|
wildcard_match_rules,
|
|
FALSE
|
|
};
|
|
|
|
static Config selective_config = {
|
|
NULL,
|
|
selective_match_rules,
|
|
FALSE
|
|
};
|
|
|
|
static Config well_known_destination_config = {
|
|
NULL,
|
|
well_known_destination_match_rules,
|
|
FALSE
|
|
};
|
|
|
|
static Config no_rules_config = {
|
|
NULL,
|
|
no_match_rules,
|
|
FALSE
|
|
};
|
|
|
|
static Config eavesdrop_config = {
|
|
NULL,
|
|
eavesdrop_match_rules,
|
|
FALSE
|
|
};
|
|
|
|
static Config no_eavesdrop_config = {
|
|
NULL,
|
|
no_eavesdrop_match_rules,
|
|
FALSE
|
|
};
|
|
|
|
#ifdef DBUS_UNIX
|
|
static Config fake_systemd_config = {
|
|
"valid-config-files/systemd-activation.conf",
|
|
NULL,
|
|
FALSE
|
|
};
|
|
#endif
|
|
|
|
static Config side_effects_config = {
|
|
NULL,
|
|
NULL,
|
|
TRUE
|
|
};
|
|
|
|
static inline const char *
|
|
not_null2 (const char *x,
|
|
const char *fallback)
|
|
{
|
|
if (x == NULL)
|
|
return fallback;
|
|
|
|
return x;
|
|
}
|
|
|
|
static inline const char *
|
|
not_null (const char *x)
|
|
{
|
|
return not_null2 (x, "(null)");
|
|
}
|
|
|
|
#define log_message(m) _log_message (m, __FILE__, __LINE__)
|
|
|
|
G_GNUC_UNUSED
|
|
static void
|
|
_log_message (DBusMessage *m,
|
|
const char *file,
|
|
int line)
|
|
{
|
|
g_test_message ("%s:%d: message type %d (%s)", file, line,
|
|
dbus_message_get_type (m),
|
|
dbus_message_type_to_string (dbus_message_get_type (m)));
|
|
g_test_message ("\tfrom: %s",
|
|
not_null2 (dbus_message_get_sender (m), "(dbus-daemon)"));
|
|
g_test_message ("\tto: %s",
|
|
not_null2 (dbus_message_get_destination (m), "(broadcast)"));
|
|
g_test_message ("\tpath: %s",
|
|
not_null (dbus_message_get_path (m)));
|
|
g_test_message ("\tinterface: %s",
|
|
not_null (dbus_message_get_interface (m)));
|
|
g_test_message ("\tmember: %s",
|
|
not_null (dbus_message_get_member (m)));
|
|
g_test_message ("\tsignature: %s",
|
|
not_null (dbus_message_get_signature (m)));
|
|
g_test_message ("\terror name: %s",
|
|
not_null (dbus_message_get_error_name (m)));
|
|
|
|
if (strcmp ("s", dbus_message_get_signature (m)) == 0)
|
|
{
|
|
DBusError e = DBUS_ERROR_INIT;
|
|
const char *s;
|
|
|
|
dbus_message_get_args (m, &e,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID);
|
|
test_assert_no_error (&e);
|
|
g_test_message ("\tstring payload: %s", s);
|
|
}
|
|
}
|
|
|
|
/* these are macros so they get the right line number */
|
|
|
|
#define assert_hello(m) \
|
|
do { \
|
|
g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
|
|
==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \
|
|
g_assert_cmpstr (dbus_message_get_destination (m), ==, DBUS_SERVICE_DBUS); \
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==, DBUS_PATH_DBUS); \
|
|
g_assert_cmpstr (dbus_message_get_interface (m), ==, DBUS_INTERFACE_DBUS); \
|
|
g_assert_cmpstr (dbus_message_get_member (m), ==, "Hello"); \
|
|
g_assert_cmpstr (dbus_message_get_signature (m), ==, ""); \
|
|
g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
|
|
g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
|
|
} while (0)
|
|
|
|
#define assert_hello_reply(m) \
|
|
do { \
|
|
DBusError _e = DBUS_ERROR_INIT; \
|
|
const char *_s; \
|
|
\
|
|
g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
|
|
==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \
|
|
g_assert_cmpstr (dbus_message_get_sender (m), ==, DBUS_SERVICE_DBUS); \
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \
|
|
g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
|
|
g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
|
|
\
|
|
dbus_message_get_args (m, &_e, \
|
|
DBUS_TYPE_STRING, &_s, \
|
|
DBUS_TYPE_INVALID); \
|
|
test_assert_no_error (&_e); \
|
|
g_assert_cmpstr (dbus_message_get_destination (m), ==, _s); \
|
|
} while (0)
|
|
|
|
#define assert_name_acquired(m) \
|
|
do { \
|
|
DBusError _e = DBUS_ERROR_INIT; \
|
|
const char *_s; \
|
|
\
|
|
g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
|
|
==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \
|
|
g_assert_cmpstr (dbus_message_get_sender (m), ==, DBUS_SERVICE_DBUS); \
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==, DBUS_PATH_DBUS); \
|
|
g_assert_cmpstr (dbus_message_get_interface (m), ==, DBUS_INTERFACE_DBUS); \
|
|
g_assert_cmpstr (dbus_message_get_member (m), ==, "NameAcquired"); \
|
|
g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \
|
|
g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
|
|
g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
|
|
\
|
|
dbus_message_get_args (m, &_e, \
|
|
DBUS_TYPE_STRING, &_s, \
|
|
DBUS_TYPE_INVALID); \
|
|
test_assert_no_error (&_e); \
|
|
g_assert_cmpstr (dbus_message_get_destination (m), ==, _s); \
|
|
} while (0)
|
|
|
|
#define assert_method_call(m, sender, \
|
|
destination, path, iface, method, signature) \
|
|
do { \
|
|
g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
|
|
==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_CALL)); \
|
|
g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
|
|
g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==, path); \
|
|
g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \
|
|
g_assert_cmpstr (dbus_message_get_member (m), ==, method); \
|
|
g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
|
|
g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
|
|
g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
|
|
} while (0)
|
|
|
|
#define assert_signal(m, \
|
|
sender, path, iface, member, signature, \
|
|
destination) \
|
|
do { \
|
|
g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
|
|
==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_SIGNAL)); \
|
|
g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
|
|
g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==, path); \
|
|
g_assert_cmpstr (dbus_message_get_interface (m), ==, iface); \
|
|
g_assert_cmpstr (dbus_message_get_member (m), ==, member); \
|
|
g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
|
|
g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
|
|
g_assert_cmpint (dbus_message_get_reply_serial (m), ==, 0); \
|
|
} while (0)
|
|
|
|
#define assert_method_reply(m, sender, destination, signature) \
|
|
do { \
|
|
g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
|
|
==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_METHOD_RETURN)); \
|
|
g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
|
|
g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_signature (m), ==, signature); \
|
|
g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
|
|
g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
|
|
} while (0)
|
|
|
|
#define assert_error_reply(m, sender, destination, error_name) \
|
|
do { \
|
|
g_assert_cmpstr (dbus_message_type_to_string (dbus_message_get_type (m)), \
|
|
==, dbus_message_type_to_string (DBUS_MESSAGE_TYPE_ERROR)); \
|
|
g_assert_cmpstr (dbus_message_get_sender (m), ==, sender); \
|
|
g_assert_cmpstr (dbus_message_get_destination (m), ==, destination); \
|
|
g_assert_cmpstr (dbus_message_get_error_name (m), ==, error_name); \
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_interface (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_member (m), ==, NULL); \
|
|
g_assert_cmpstr (dbus_message_get_signature (m), ==, "s"); \
|
|
g_assert_cmpint (dbus_message_get_serial (m), !=, 0); \
|
|
g_assert_cmpint (dbus_message_get_reply_serial (m), !=, 0); \
|
|
} while (0)
|
|
|
|
/* This is called after processing pending replies to our own method
|
|
* calls, but before anything else.
|
|
*/
|
|
static DBusHandlerResult
|
|
monitor_filter (DBusConnection *connection,
|
|
DBusMessage *message,
|
|
void *user_data)
|
|
{
|
|
Fixture *f = user_data;
|
|
|
|
g_assert_cmpstr (dbus_message_get_interface (message), !=,
|
|
"com.example.Tedious");
|
|
|
|
/* we are not interested in the monitor getting NameAcquired or NameLost
|
|
* for most tests */
|
|
if (f->config == NULL || !f->config->care_about_our_names)
|
|
{
|
|
if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
|
|
"NameAcquired") ||
|
|
dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
|
|
"NameLost"))
|
|
{
|
|
DBusError e = DBUS_ERROR_INIT;
|
|
const char *s;
|
|
|
|
dbus_message_get_args (message, &e,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID);
|
|
test_assert_no_error (&e);
|
|
|
|
if (strcmp (s, f->monitor_name) == 0)
|
|
{
|
|
/* ignore */
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_queue_push_tail (&f->monitored, dbus_message_ref (message));
|
|
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
|
|
static DBusHandlerResult
|
|
recipient_filter (DBusConnection *connection,
|
|
DBusMessage *message,
|
|
void *user_data)
|
|
{
|
|
g_assert_cmpstr (dbus_message_get_interface (message), !=,
|
|
"com.example.CannotSend");
|
|
g_assert_cmpstr (dbus_message_get_interface (message), !=,
|
|
"com.example.CannotReceive");
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
static DBusHandlerResult
|
|
systemd_filter (DBusConnection *connection,
|
|
DBusMessage *message,
|
|
void *user_data)
|
|
{
|
|
Fixture *f = user_data;
|
|
|
|
if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
|
|
"NameAcquired") ||
|
|
dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
|
|
"NameLost"))
|
|
{
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
g_assert (f->systemd_message == NULL);
|
|
f->systemd_message = dbus_message_ref (message);
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
static DBusHandlerResult
|
|
activated_filter (DBusConnection *connection,
|
|
DBusMessage *message,
|
|
void *user_data)
|
|
{
|
|
Fixture *f = user_data;
|
|
|
|
if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
|
|
"NameAcquired") ||
|
|
dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
|
|
"NameLost"))
|
|
{
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
g_assert (f->activated_message == NULL);
|
|
f->activated_message = dbus_message_ref (message);
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
static void
|
|
take_well_known_name (Fixture *f,
|
|
DBusConnection *connection,
|
|
const char *name)
|
|
{
|
|
int ret;
|
|
|
|
ret = dbus_bus_request_name (connection, name,
|
|
DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
|
|
test_assert_no_error (&f->e);
|
|
g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
|
|
}
|
|
|
|
static void
|
|
setup (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
f->config = context;
|
|
|
|
f->ctx = test_main_context_get ();
|
|
|
|
f->ge = NULL;
|
|
dbus_error_init (&f->e);
|
|
|
|
f->address = test_get_dbus_daemon (f->config ? f->config->config_file : NULL,
|
|
TEST_USER_ME, NULL, &f->daemon_pid);
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
f->monitor = test_connect_to_bus (f->ctx, f->address);
|
|
f->monitor_name = dbus_bus_get_unique_name (f->monitor);
|
|
f->sender = test_connect_to_bus (f->ctx, f->address);
|
|
f->sender_name = dbus_bus_get_unique_name (f->sender);
|
|
f->recipient = test_connect_to_bus (f->ctx, f->address);
|
|
f->recipient_name = dbus_bus_get_unique_name (f->recipient);
|
|
|
|
if (!dbus_connection_add_filter (f->monitor, monitor_filter, f, NULL))
|
|
g_error ("OOM");
|
|
|
|
if (!dbus_connection_add_filter (f->recipient, recipient_filter, f, NULL))
|
|
g_error ("OOM");
|
|
}
|
|
|
|
static void
|
|
become_monitor (Fixture *f,
|
|
const Config *config)
|
|
{
|
|
DBusMessage *m;
|
|
DBusPendingCall *pc;
|
|
dbus_bool_t ok;
|
|
DBusMessageIter appender, array_appender;
|
|
const char * const *match_rules;
|
|
int i;
|
|
dbus_uint32_t zero = 0;
|
|
|
|
dbus_connection_set_route_peer_messages (f->monitor, TRUE);
|
|
|
|
if (config == NULL)
|
|
config = f->config;
|
|
|
|
if (config != NULL && config->match_rules != NULL)
|
|
match_rules = config->match_rules;
|
|
else
|
|
match_rules = wildcard_match_rules;
|
|
|
|
m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
|
|
DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor");
|
|
|
|
if (m == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_iter_init_append (m, &appender);
|
|
|
|
if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s",
|
|
&array_appender))
|
|
g_error ("OOM");
|
|
|
|
for (i = 0; match_rules[i] != NULL; i++)
|
|
{
|
|
if (!dbus_message_iter_append_basic (&array_appender, DBUS_TYPE_STRING,
|
|
&match_rules[i]))
|
|
g_error ("OOM");
|
|
}
|
|
|
|
if (!dbus_message_iter_close_container (&appender, &array_appender) ||
|
|
!dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &zero))
|
|
g_error ("OOM");
|
|
|
|
if (!dbus_connection_send_with_reply (f->monitor, m, &pc,
|
|
DBUS_TIMEOUT_USE_DEFAULT) ||
|
|
pc == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_unref (m);
|
|
m = NULL;
|
|
|
|
if (dbus_pending_call_get_completed (pc))
|
|
test_pending_call_store_reply (pc, &m);
|
|
else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
|
|
&m, NULL))
|
|
g_error ("OOM");
|
|
|
|
while (m == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
ok = dbus_message_get_args (m, &f->e,
|
|
DBUS_TYPE_INVALID);
|
|
test_assert_no_error (&f->e);
|
|
g_assert (ok);
|
|
|
|
dbus_pending_call_unref (pc);
|
|
dbus_message_unref (m);
|
|
m = NULL;
|
|
}
|
|
|
|
/*
|
|
* Test what happens if the method call arguments are invalid.
|
|
*/
|
|
static void
|
|
test_invalid (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
DBusPendingCall *pc;
|
|
dbus_bool_t ok;
|
|
DBusMessageIter appender, array_appender;
|
|
dbus_uint32_t zero = 0;
|
|
dbus_uint32_t invalid_flags = G_MAXUINT32;
|
|
const char *s;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
dbus_connection_set_route_peer_messages (f->monitor, TRUE);
|
|
|
|
/* Try to become a monitor but specify nonzero flags - not allowed */
|
|
|
|
m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
|
|
DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor");
|
|
|
|
if (m == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_iter_init_append (m, &appender);
|
|
|
|
if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s",
|
|
&array_appender))
|
|
g_error ("OOM");
|
|
|
|
if (!dbus_message_iter_close_container (&appender, &array_appender) ||
|
|
!dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32,
|
|
&invalid_flags))
|
|
g_error ("OOM");
|
|
|
|
if (!dbus_connection_send_with_reply (f->monitor, m, &pc,
|
|
DBUS_TIMEOUT_USE_DEFAULT) ||
|
|
pc == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_unref (m);
|
|
m = NULL;
|
|
|
|
if (dbus_pending_call_get_completed (pc))
|
|
test_pending_call_store_reply (pc, &m);
|
|
else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
|
|
&m, NULL))
|
|
g_error ("OOM");
|
|
|
|
while (m == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR);
|
|
g_assert_cmpstr (dbus_message_get_error_name (m), ==,
|
|
DBUS_ERROR_INVALID_ARGS);
|
|
|
|
/* Try to become a monitor but use the wrong object path - not allowed
|
|
* (security hardening against inappropriate XML policy rules) */
|
|
|
|
dbus_pending_call_unref (pc);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
|
|
"/", DBUS_INTERFACE_MONITORING, "BecomeMonitor");
|
|
|
|
if (m == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_iter_init_append (m, &appender);
|
|
|
|
if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s",
|
|
&array_appender))
|
|
g_error ("OOM");
|
|
|
|
if (!dbus_message_iter_close_container (&appender, &array_appender) ||
|
|
!dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &zero))
|
|
g_error ("OOM");
|
|
|
|
if (!dbus_connection_send_with_reply (f->monitor, m, &pc,
|
|
DBUS_TIMEOUT_USE_DEFAULT) ||
|
|
pc == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_unref (m);
|
|
m = NULL;
|
|
|
|
if (dbus_pending_call_get_completed (pc))
|
|
test_pending_call_store_reply (pc, &m);
|
|
else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
|
|
&m, NULL))
|
|
g_error ("OOM");
|
|
|
|
while (m == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR);
|
|
g_assert_cmpstr (dbus_message_get_error_name (m), ==,
|
|
DBUS_ERROR_UNKNOWN_INTERFACE);
|
|
|
|
/* Try to become a monitor but specify a bad match rule -
|
|
* also not allowed */
|
|
|
|
dbus_pending_call_unref (pc);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
|
|
DBUS_PATH_DBUS, DBUS_INTERFACE_MONITORING, "BecomeMonitor");
|
|
|
|
if (m == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_iter_init_append (m, &appender);
|
|
|
|
if (!dbus_message_iter_open_container (&appender, DBUS_TYPE_ARRAY, "s",
|
|
&array_appender))
|
|
g_error ("OOM");
|
|
|
|
/* Syntactically incorrect match rule taken from #92298 - was probably
|
|
* intended to be path='/modules/...'
|
|
*/
|
|
s = "interface='org.kde.walletd',member='/modules/kwalletd/org.kde.KWallet/walletOpened'";
|
|
|
|
if (!dbus_message_iter_append_basic (&array_appender, DBUS_TYPE_STRING,
|
|
&s) ||
|
|
!dbus_message_iter_close_container (&appender, &array_appender) ||
|
|
!dbus_message_iter_append_basic (&appender, DBUS_TYPE_UINT32, &zero) ||
|
|
!dbus_connection_send_with_reply (f->monitor, m, &pc,
|
|
DBUS_TIMEOUT_USE_DEFAULT) ||
|
|
pc == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_unref (m);
|
|
m = NULL;
|
|
|
|
if (dbus_pending_call_get_completed (pc))
|
|
test_pending_call_store_reply (pc, &m);
|
|
else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
|
|
&m, NULL))
|
|
g_error ("OOM");
|
|
|
|
while (m == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
g_assert_cmpint (dbus_message_get_type (m), ==, DBUS_MESSAGE_TYPE_ERROR);
|
|
g_assert_cmpstr (dbus_message_get_error_name (m), ==,
|
|
DBUS_ERROR_MATCH_RULE_INVALID);
|
|
|
|
dbus_pending_call_unref (pc);
|
|
dbus_message_unref (m);
|
|
|
|
/* We did not become a monitor, so we can still call methods. */
|
|
|
|
pc = NULL;
|
|
m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
|
|
DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetId");
|
|
|
|
if (m == NULL)
|
|
g_error ("OOM");
|
|
|
|
if (!dbus_connection_send_with_reply (f->monitor, m, &pc,
|
|
DBUS_TIMEOUT_USE_DEFAULT) ||
|
|
pc == NULL)
|
|
g_error ("OOM");
|
|
|
|
dbus_message_unref (m);
|
|
m = NULL;
|
|
|
|
if (dbus_pending_call_get_completed (pc))
|
|
test_pending_call_store_reply (pc, &m);
|
|
else if (!dbus_pending_call_set_notify (pc, test_pending_call_store_reply,
|
|
&m, NULL))
|
|
g_error ("OOM");
|
|
|
|
while (m == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
if (dbus_set_error_from_message (&f->e, m))
|
|
g_error ("%s: %s", f->e.name, f->e.message);
|
|
|
|
ok = dbus_message_get_args (m, &f->e,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID);
|
|
test_assert_no_error (&f->e);
|
|
g_assert (ok);
|
|
g_assert_cmpstr (s, !=, NULL);
|
|
g_assert_cmpstr (s, !=, "");
|
|
|
|
dbus_pending_call_unref (pc);
|
|
dbus_message_unref (m);
|
|
}
|
|
|
|
/*
|
|
* Test the side-effects of becoming a monitor.
|
|
*/
|
|
static void
|
|
test_become_monitor (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
int ret;
|
|
dbus_bool_t got_unique = FALSE, got_a = FALSE, got_b = FALSE, got_c = FALSE;
|
|
dbus_bool_t lost_unique = FALSE, lost_a = FALSE, lost_b = FALSE, lost_c = FALSE;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
ret = dbus_bus_request_name (f->monitor, "com.example.A",
|
|
DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
|
|
test_assert_no_error (&f->e);
|
|
g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
|
|
|
|
ret = dbus_bus_request_name (f->monitor, "com.example.B",
|
|
DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
|
|
test_assert_no_error (&f->e);
|
|
g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
|
|
|
|
ret = dbus_bus_request_name (f->monitor, "com.example.C",
|
|
DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
|
|
test_assert_no_error (&f->e);
|
|
g_assert_cmpint (ret, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
|
|
|
|
while (!got_unique || !got_a || !got_b || !got_c)
|
|
{
|
|
if (g_queue_is_empty (&f->monitored))
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
while ((m = g_queue_pop_head (&f->monitored)) != NULL)
|
|
{
|
|
if (dbus_message_is_signal (m, DBUS_INTERFACE_DBUS,
|
|
"NameAcquired"))
|
|
{
|
|
const char *name;
|
|
dbus_bool_t ok = dbus_message_get_args (m, &f->e,
|
|
DBUS_TYPE_STRING, &name,
|
|
DBUS_TYPE_INVALID);
|
|
|
|
g_assert_cmpstr (dbus_message_get_path (m), ==,
|
|
DBUS_PATH_DBUS);
|
|
|
|
test_assert_no_error (&f->e);
|
|
g_assert (ok);
|
|
|
|
if (g_str_equal (name, f->monitor_name))
|
|
{
|
|
g_assert (!got_unique);
|
|
got_unique = TRUE;
|
|
}
|
|
else if (g_str_equal (name, "com.example.A"))
|
|
{
|
|
g_assert (!got_a);
|
|
got_a = TRUE;
|
|
}
|
|
else if (g_str_equal (name, "com.example.B"))
|
|
{
|
|
g_assert (!got_b);
|
|
got_b = TRUE;
|
|
}
|
|
else
|
|
{
|
|
g_assert_cmpstr (name, ==, "com.example.C");
|
|
g_assert (!got_c);
|
|
got_c = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_error ("unexpected message %s.%s",
|
|
dbus_message_get_interface (m),
|
|
dbus_message_get_member (m));
|
|
}
|
|
|
|
dbus_message_unref (m);
|
|
}
|
|
}
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
while (!lost_unique || !lost_a || !lost_b || !lost_c)
|
|
{
|
|
if (g_queue_is_empty (&f->monitored))
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
while ((m = g_queue_pop_head (&f->monitored)) != NULL)
|
|
{
|
|
if (dbus_message_is_signal (m, DBUS_INTERFACE_DBUS,
|
|
"NameLost"))
|
|
{
|
|
const char *name;
|
|
dbus_bool_t ok = dbus_message_get_args (m, &f->e,
|
|
DBUS_TYPE_STRING, &name,
|
|
DBUS_TYPE_INVALID);
|
|
|
|
test_assert_no_error (&f->e);
|
|
g_assert (ok);
|
|
|
|
if (g_str_equal (name, f->monitor_name))
|
|
{
|
|
g_assert (!lost_unique);
|
|
lost_unique = TRUE;
|
|
}
|
|
else if (g_str_equal (name, "com.example.A"))
|
|
{
|
|
g_assert (!lost_a);
|
|
lost_a = TRUE;
|
|
}
|
|
else if (g_str_equal (name, "com.example.B"))
|
|
{
|
|
g_assert (!lost_b);
|
|
lost_b = TRUE;
|
|
}
|
|
else
|
|
{
|
|
g_assert_cmpstr (name, ==, "com.example.C");
|
|
g_assert (!lost_c);
|
|
lost_c = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_error ("unexpected message %s.%s",
|
|
dbus_message_get_interface (m),
|
|
dbus_message_get_member (m));
|
|
}
|
|
|
|
dbus_message_unref (m);
|
|
}
|
|
}
|
|
|
|
/* Calling methods is forbidden; we get disconnected. */
|
|
dbus_bus_add_match (f->monitor, "", &f->e);
|
|
g_assert_cmpstr (f->e.name, ==, DBUS_ERROR_NO_REPLY);
|
|
g_assert (!dbus_connection_get_is_connected (f->monitor));
|
|
|
|
while (TRUE)
|
|
{
|
|
if (g_queue_is_empty (&f->monitored))
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
/* When we iterate all the connection's messages, we see ourselves
|
|
* losing all our names, then we're disconnected. */
|
|
while ((m = g_queue_pop_head (&f->monitored)) != NULL)
|
|
{
|
|
if (dbus_message_is_signal (m, DBUS_INTERFACE_LOCAL, "Disconnected"))
|
|
{
|
|
dbus_message_unref (m);
|
|
goto disconnected;
|
|
}
|
|
else
|
|
{
|
|
g_error ("unexpected message %s.%s",
|
|
dbus_message_get_interface (m),
|
|
dbus_message_get_member (m));
|
|
}
|
|
|
|
dbus_message_unref (m);
|
|
}
|
|
}
|
|
|
|
disconnected:
|
|
|
|
g_assert (lost_a);
|
|
g_assert (lost_b);
|
|
g_assert (lost_c);
|
|
}
|
|
|
|
static void
|
|
test_broadcast (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
dbus_bus_add_match (f->recipient, "type='signal'", &f->e);
|
|
test_assert_no_error (&f->e);
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal1");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal2");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "BroadcastSignal3");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 3)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.bar",
|
|
"BroadcastSignal1", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.bar",
|
|
"BroadcastSignal2", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.bar",
|
|
"BroadcastSignal3", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_forbidden_broadcast (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
dbus_bus_add_match (f->recipient, "type='signal'", &f->e);
|
|
test_assert_no_error (&f->e);
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
|
|
"BroadcastSignal1");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotReceive",
|
|
"BroadcastSignal2");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
|
|
"BroadcastSignal3");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 6)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend",
|
|
"BroadcastSignal1", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotReceive",
|
|
"BroadcastSignal2", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotSend",
|
|
"BroadcastSignal3", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_unicast_signal (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 3)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal1", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal2", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal3", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_forbidden (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
|
|
"UnicastSignal1");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotReceive",
|
|
"UnicastSignal2");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotSend",
|
|
"UnicastSignal3");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 6)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.CannotSend", "UnicastSignal1", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.CannotReceive", "UnicastSignal2", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.CannotSend", "UnicastSignal3", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_method_call (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
/* regression test for
|
|
* https://bugs.freedesktop.org/show_bug.cgi?id=90952 */
|
|
m = dbus_message_new_method_call (f->recipient_name, "/foo",
|
|
DBUS_INTERFACE_PEER, "Ping");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
|
|
DBUS_INTERFACE_PEER, "Ping", "");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_reply (m, f->recipient_name, f->sender_name, "");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
|
|
m = dbus_message_new_method_call (f->recipient_name, "/foo", "com.example.bar",
|
|
"Call1");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
|
|
"com.example.bar", "Call1", "");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, f->recipient_name, f->sender_name,
|
|
DBUS_ERROR_UNKNOWN_METHOD);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_forbidden_method_call (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
m = dbus_message_new_method_call (f->recipient_name, "/foo",
|
|
"com.example.CannotSend", "Call1");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
|
|
"com.example.CannotSend", "Call1", "");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
|
|
m = dbus_message_new_method_call (f->recipient_name, "/foo",
|
|
"com.example.CannotReceive", "Call2");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_call (m, f->sender_name, f->recipient_name, "/foo",
|
|
"com.example.CannotReceive", "Call2", "");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
DBUS_ERROR_ACCESS_DENIED);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_dbus_daemon (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
int res;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
res = dbus_bus_request_name (f->sender, "com.example.Sender",
|
|
DBUS_NAME_FLAG_DO_NOT_QUEUE, &f->e);
|
|
test_assert_no_error (&f->e);
|
|
g_assert_cmpint (res, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER);
|
|
|
|
res = dbus_bus_release_name (f->sender, "com.example.Sender", &f->e);
|
|
test_assert_no_error (&f->e);
|
|
g_assert_cmpint (res, ==, DBUS_RELEASE_NAME_REPLY_RELEASED);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 8)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_call (m, f->sender_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
DBUS_INTERFACE_DBUS, "RequestName", "su");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
|
|
"NameOwnerChanged", "sss", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* FIXME: should we get this? */
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
|
|
"NameAcquired", "s", f->sender_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_reply (m, DBUS_SERVICE_DBUS, f->sender_name, "u");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_call (m, f->sender_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
DBUS_INTERFACE_DBUS, "ReleaseName", "s");
|
|
dbus_message_unref (m);
|
|
|
|
/* FIXME: should we get this? */
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
|
|
"NameLost", "s", f->sender_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
|
|
"NameOwnerChanged", "sss", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_reply (m, DBUS_SERVICE_DBUS, f->sender_name, "u");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_selective (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
/* Match rules added before becoming a monitor should be cleared:
|
|
* if they weren't, this test would get Interesting twice, then Tedious,
|
|
* and only see Fun after that. */
|
|
dbus_bus_add_match (f->monitor,
|
|
"eavesdrop='true',interface='com.example.Interesting'", &f->e);
|
|
test_assert_no_error (&f->e);
|
|
dbus_bus_add_match (f->monitor,
|
|
"eavesdrop='true',interface='com.example.Tedious'", &f->e);
|
|
test_assert_no_error (&f->e);
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.Interesting",
|
|
"UnicastSignal1");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.Tedious",
|
|
"UnicastSignal2");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.Fun",
|
|
"UnicastSignal3");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
/* We get the interesting signal and the fun signal, but not the tedious
|
|
* signal. */
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.Interesting", "UnicastSignal1", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.Fun", "UnicastSignal3", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_well_known_destination (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
take_well_known_name (f, f->recipient, "com.example.Recipient");
|
|
/* we don't expect_take_well_known_name here because the
|
|
* monitor isn't up yet */
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
/* The sender sends a message to itself. It will not be observed. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "Unobserved");
|
|
if (!dbus_message_set_destination (m, f->sender_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* The sender sends a message to the recipient by well-known name.
|
|
* It will be observed. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "Observed1");
|
|
if (!dbus_message_set_destination (m, "com.example.Recipient"))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* The sender sends a message to the recipient by unique name.
|
|
* It will still be observed. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "Observed2");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.bar",
|
|
"Observed1", "", "com.example.Recipient");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.bar",
|
|
"Observed2", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
static void
|
|
test_unique_destination (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
Config config = {
|
|
NULL,
|
|
NULL, /* match rules */
|
|
FALSE
|
|
};
|
|
const gchar *match_rules[2] = { NULL, NULL };
|
|
gchar *rule;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
take_well_known_name (f, f->recipient, "com.example.Recipient");
|
|
/* we don't expect_take_well_known_name here because the
|
|
* monitor isn't up yet */
|
|
|
|
rule = g_strdup_printf ("destination='%s'", f->recipient_name);
|
|
/* free it later */
|
|
g_test_queue_free (rule);
|
|
match_rules[0] = rule;
|
|
config.match_rules = match_rules;
|
|
|
|
become_monitor (f, &config);
|
|
|
|
/* The sender sends a message to itself. It will not be observed. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "Unobserved");
|
|
if (!dbus_message_set_destination (m, f->sender_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* The sender sends a message to the recipient by well-known name.
|
|
* It will be observed. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "Observed1");
|
|
if (!dbus_message_set_destination (m, "com.example.Recipient"))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* The sender sends a message to the recipient by unique name.
|
|
* It will still be observed. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "Observed2");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.bar",
|
|
"Observed1", "", "com.example.Recipient");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.bar",
|
|
"Observed2", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
}
|
|
|
|
#ifdef DBUS_UNIX
|
|
/* currently only used for the systemd activation test */
|
|
static void
|
|
expect_new_connection (Fixture *f)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
while (g_queue_get_length (&f->monitored) < 4)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_hello (m);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_hello_reply (m);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
|
|
"NameOwnerChanged", "sss", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_name_acquired (m);
|
|
dbus_message_unref (m);
|
|
}
|
|
|
|
/* currently only used for the systemd activation test */
|
|
static void
|
|
expect_take_well_known_name (Fixture *f,
|
|
DBusConnection *connection,
|
|
const char *name)
|
|
{
|
|
DBusMessage *m;
|
|
const char *connection_name = dbus_bus_get_unique_name (connection);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 4)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_call (m, connection_name, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
DBUS_INTERFACE_DBUS, "RequestName", "su");
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
|
|
"NameOwnerChanged", "sss", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
|
|
"NameAcquired", "s", connection_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_method_reply (m, DBUS_SERVICE_DBUS, connection_name, "u");
|
|
dbus_message_unref (m);
|
|
}
|
|
|
|
static void
|
|
test_activation (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m;
|
|
|
|
if (f->address == NULL)
|
|
return;
|
|
|
|
become_monitor (f, NULL);
|
|
|
|
/* The sender sends a message to an activatable service. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal1");
|
|
if (!dbus_message_set_destination (m, "com.example.SystemdActivatable1"))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* We observe the activation request, and the message that caused it,
|
|
* before systemd has even joined the bus. */
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
"org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
|
|
"org.freedesktop.systemd1");
|
|
dbus_message_unref (m);
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal1", "",
|
|
"com.example.SystemdActivatable1");
|
|
dbus_message_unref (m);
|
|
|
|
/* The fake systemd connects to the bus. */
|
|
f->systemd = test_connect_to_bus (f->ctx, f->address);
|
|
if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
|
|
g_error ("OOM");
|
|
f->systemd_name = dbus_bus_get_unique_name (f->systemd);
|
|
|
|
expect_new_connection (f);
|
|
take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
|
|
expect_take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
|
|
|
|
/* It gets its activation request. */
|
|
while (f->systemd_message == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = f->systemd_message;
|
|
f->systemd_message = NULL;
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
"org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
|
|
"org.freedesktop.systemd1");
|
|
dbus_message_unref (m);
|
|
|
|
/* systemd starts the activatable service. */
|
|
f->activated = test_connect_to_bus (f->ctx, f->address);
|
|
if (!dbus_connection_add_filter (f->activated, activated_filter,
|
|
f, NULL))
|
|
g_error ("OOM");
|
|
f->activated_name = dbus_bus_get_unique_name (f->activated);
|
|
|
|
expect_new_connection (f);
|
|
take_well_known_name (f, f->activated, "com.example.SystemdActivatable1");
|
|
expect_take_well_known_name (f, f->activated,
|
|
"com.example.SystemdActivatable1");
|
|
|
|
/* The message is delivered to the activatable service. */
|
|
while (f->activated_message == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = f->activated_message;
|
|
f->activated_message = NULL;
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal1", "",
|
|
"com.example.SystemdActivatable1");
|
|
dbus_message_unref (m);
|
|
|
|
/* The sender sends a message to a different activatable service. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal2");
|
|
if (!dbus_message_set_destination (m, "com.example.SystemdActivatable2"))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* This time systemd is already ready for it. */
|
|
while (g_queue_get_length (&f->monitored) < 2 ||
|
|
f->systemd_message == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = f->systemd_message;
|
|
f->systemd_message = NULL;
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
"org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
|
|
"org.freedesktop.systemd1");
|
|
dbus_message_unref (m);
|
|
|
|
/* The monitor sees the activation request and the signal that
|
|
* prompted it.*/
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
"org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
|
|
"org.freedesktop.systemd1");
|
|
dbus_message_unref (m);
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal2", "",
|
|
"com.example.SystemdActivatable2");
|
|
dbus_message_unref (m);
|
|
|
|
/* The activatable service takes its name. Here I'm faking it by using
|
|
* an existing connection. */
|
|
take_well_known_name (f, f->activated, "com.example.SystemdActivatable2");
|
|
|
|
/* The message is delivered to the activatable service.
|
|
* Implementation detail: the monitor sees this happen before it even
|
|
* sees that the name request happened, which is pretty odd. */
|
|
while (f->activated_message == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = f->activated_message;
|
|
f->activated_message = NULL;
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal2", "",
|
|
"com.example.SystemdActivatable2");
|
|
dbus_message_unref (m);
|
|
|
|
expect_take_well_known_name (f, f->activated,
|
|
"com.example.SystemdActivatable2");
|
|
|
|
/* A third activation. */
|
|
m = dbus_message_new_signal ("/foo", "com.example.bar", "UnicastSignal3");
|
|
if (!dbus_message_set_destination (m, "com.example.SystemdActivatable3"))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* Once again, we see the activation request and the reason. */
|
|
while (g_queue_get_length (&f->monitored) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
"org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
|
|
"org.freedesktop.systemd1");
|
|
dbus_message_unref (m);
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo",
|
|
"com.example.bar", "UnicastSignal3", "",
|
|
"com.example.SystemdActivatable3");
|
|
dbus_message_unref (m);
|
|
|
|
/* systemd gets the request too. */
|
|
while (f->systemd_message == NULL)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = f->systemd_message;
|
|
f->systemd_message = NULL;
|
|
assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
|
"org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
|
|
"org.freedesktop.systemd1");
|
|
dbus_message_unref (m);
|
|
|
|
/* This time activation fails */
|
|
m = dbus_message_new_signal ("/org/freedesktop/systemd1",
|
|
"org.freedesktop.systemd1.Activator", "ActivationFailure");
|
|
|
|
do
|
|
{
|
|
const char *unit = "dbus-com.example.SystemdActivatable3.service";
|
|
const char *error_name = "com.example.Nope";
|
|
const char *error_message = "Computer says no";
|
|
|
|
if (!dbus_message_append_args (m,
|
|
DBUS_TYPE_STRING, &unit,
|
|
DBUS_TYPE_STRING, &error_name,
|
|
DBUS_TYPE_STRING, &error_message,
|
|
DBUS_TYPE_INVALID))
|
|
g_error ("OOM");
|
|
}
|
|
while (0);
|
|
|
|
if (!dbus_message_set_destination (m, "org.freedesktop.DBus"))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->systemd, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* The monitor sees activation fail */
|
|
|
|
/* Once again, we see the activation request and the reason. */
|
|
while (g_queue_get_length (&f->monitored) < 1)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_error_reply (m, DBUS_SERVICE_DBUS, f->sender_name,
|
|
"com.example.Nope");
|
|
dbus_message_unref (m);
|
|
}
|
|
#endif /* DBUS_UNIX */
|
|
|
|
static void
|
|
teardown (Fixture *f,
|
|
gconstpointer context G_GNUC_UNUSED)
|
|
{
|
|
dbus_error_free (&f->e);
|
|
g_clear_error (&f->ge);
|
|
|
|
if (f->monitor != NULL)
|
|
{
|
|
dbus_connection_remove_filter (f->monitor, monitor_filter, f);
|
|
dbus_connection_close (f->monitor);
|
|
dbus_connection_unref (f->monitor);
|
|
f->monitor = NULL;
|
|
}
|
|
|
|
if (f->sender != NULL)
|
|
{
|
|
dbus_connection_close (f->sender);
|
|
dbus_connection_unref (f->sender);
|
|
f->sender = NULL;
|
|
}
|
|
|
|
if (f->recipient != NULL)
|
|
{
|
|
dbus_connection_remove_filter (f->recipient, recipient_filter, f);
|
|
dbus_connection_close (f->recipient);
|
|
dbus_connection_unref (f->recipient);
|
|
f->recipient = NULL;
|
|
}
|
|
|
|
if (f->systemd != NULL)
|
|
{
|
|
dbus_connection_remove_filter (f->systemd, systemd_filter, f);
|
|
dbus_connection_close (f->systemd);
|
|
dbus_connection_unref (f->systemd);
|
|
f->systemd = NULL;
|
|
}
|
|
|
|
if (f->activated != NULL)
|
|
{
|
|
dbus_connection_remove_filter (f->activated, activated_filter, f);
|
|
dbus_connection_close (f->activated);
|
|
dbus_connection_unref (f->activated);
|
|
f->activated = NULL;
|
|
}
|
|
|
|
if (f->daemon_pid != 0)
|
|
{
|
|
test_kill_pid (f->daemon_pid);
|
|
g_spawn_close_pid (f->daemon_pid);
|
|
f->daemon_pid = 0;
|
|
}
|
|
|
|
test_main_context_unref (f->ctx);
|
|
|
|
g_queue_foreach (&f->monitored, (GFunc) dbus_message_unref, NULL);
|
|
g_queue_clear (&f->monitored);
|
|
|
|
g_free (f->address);
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char **argv)
|
|
{
|
|
test_init (&argc, &argv);
|
|
|
|
g_test_add ("/monitor/invalid", Fixture, NULL,
|
|
setup, test_invalid, teardown);
|
|
g_test_add ("/monitor/become", Fixture, &side_effects_config,
|
|
setup, test_become_monitor, teardown);
|
|
g_test_add ("/monitor/broadcast", Fixture, NULL,
|
|
setup, test_broadcast, teardown);
|
|
g_test_add ("/monitor/forbidden-broadcast", Fixture, &forbidding_config,
|
|
setup, test_forbidden_broadcast, teardown);
|
|
g_test_add ("/monitor/unicast-signal", Fixture, NULL,
|
|
setup, test_unicast_signal, teardown);
|
|
g_test_add ("/monitor/forbidden", Fixture, &forbidding_config,
|
|
setup, test_forbidden, teardown);
|
|
g_test_add ("/monitor/method-call", Fixture, NULL,
|
|
setup, test_method_call, teardown);
|
|
g_test_add ("/monitor/forbidden-method", Fixture, &forbidding_config,
|
|
setup, test_forbidden_method_call, teardown);
|
|
g_test_add ("/monitor/dbus-daemon", Fixture, NULL,
|
|
setup, test_dbus_daemon, teardown);
|
|
g_test_add ("/monitor/selective", Fixture, &selective_config,
|
|
setup, test_selective, teardown);
|
|
g_test_add ("/monitor/well-known-destination",
|
|
Fixture, &well_known_destination_config,
|
|
setup, test_well_known_destination, teardown);
|
|
g_test_add ("/monitor/unique-destination",
|
|
Fixture, NULL,
|
|
setup, test_unique_destination, teardown);
|
|
g_test_add ("/monitor/wildcard", Fixture, &wildcard_config,
|
|
setup, test_unicast_signal, teardown);
|
|
g_test_add ("/monitor/no-rule", Fixture, &no_rules_config,
|
|
setup, test_unicast_signal, teardown);
|
|
g_test_add ("/monitor/eavesdrop", Fixture, &eavesdrop_config,
|
|
setup, test_unicast_signal, teardown);
|
|
g_test_add ("/monitor/no-eavesdrop", Fixture, &no_eavesdrop_config,
|
|
setup, test_unicast_signal, teardown);
|
|
|
|
#ifdef DBUS_UNIX
|
|
/* this relies on the systemd activation code path */
|
|
g_test_add ("/monitor/activation", Fixture, &fake_systemd_config,
|
|
setup, test_activation, teardown);
|
|
#endif
|
|
|
|
return g_test_run ();
|
|
}
|