2013 lines
61 KiB
C
2013 lines
61 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;
|
|
gboolean recipient_enqueue_filter_added;
|
|
|
|
GQueue monitored;
|
|
GQueue received;
|
|
|
|
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_check_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
|
|
recipient_enqueue_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") ||
|
|
dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
|
|
"NameOwnerChanged"))
|
|
{
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
g_queue_push_tail (&f->received, dbus_message_ref (message));
|
|
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_check_filter,
|
|
f, NULL))
|
|
g_error ("OOM");
|
|
}
|
|
|
|
static void
|
|
become_monitor (Fixture *f,
|
|
const Config *config)
|
|
{
|
|
DBusMessage *m = NULL;
|
|
DBusMessage *reply = NULL;
|
|
dbus_bool_t ok;
|
|
DBusMessageIter appender, array_appender;
|
|
const char * const *match_rules;
|
|
int i;
|
|
dbus_uint32_t zero = 0;
|
|
|
|
dbus_connection_set_builtin_filters_enabled (f->monitor, FALSE);
|
|
|
|
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");
|
|
|
|
reply = test_main_context_call_and_wait (f->ctx, f->monitor, m,
|
|
DBUS_TIMEOUT_USE_DEFAULT);
|
|
|
|
ok = dbus_message_get_args (reply, &f->e,
|
|
DBUS_TYPE_INVALID);
|
|
test_assert_no_error (&f->e);
|
|
g_assert (ok);
|
|
|
|
dbus_clear_message (&reply);
|
|
dbus_clear_message (&m);
|
|
}
|
|
|
|
/*
|
|
* Test what happens if the method call arguments are invalid.
|
|
*/
|
|
static void
|
|
test_invalid (Fixture *f,
|
|
gconstpointer context)
|
|
{
|
|
DBusMessage *m = NULL;
|
|
DBusMessage *reply = NULL;
|
|
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");
|
|
|
|
reply = test_main_context_call_and_wait (f->ctx, f->monitor, m,
|
|
DBUS_TIMEOUT_USE_DEFAULT);
|
|
|
|
g_assert_cmpint (dbus_message_get_type (reply), ==, DBUS_MESSAGE_TYPE_ERROR);
|
|
g_assert_cmpstr (dbus_message_get_error_name (reply), ==,
|
|
DBUS_ERROR_INVALID_ARGS);
|
|
|
|
dbus_clear_message (&reply);
|
|
dbus_clear_message (&m);
|
|
|
|
/* Try to become a monitor but use the wrong object path - not allowed
|
|
* (security hardening against inappropriate XML policy rules) */
|
|
|
|
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");
|
|
|
|
reply = test_main_context_call_and_wait (f->ctx, f->monitor, m,
|
|
DBUS_TIMEOUT_USE_DEFAULT);
|
|
|
|
g_assert_cmpint (dbus_message_get_type (reply), ==, DBUS_MESSAGE_TYPE_ERROR);
|
|
g_assert_cmpstr (dbus_message_get_error_name (reply), ==,
|
|
DBUS_ERROR_UNKNOWN_INTERFACE);
|
|
|
|
dbus_clear_message (&reply);
|
|
dbus_clear_message (&m);
|
|
|
|
/* Try to become a monitor but specify a bad match rule -
|
|
* also 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");
|
|
|
|
/* 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))
|
|
test_oom ();
|
|
|
|
reply = test_main_context_call_and_wait (f->ctx, f->monitor, m,
|
|
DBUS_TIMEOUT_USE_DEFAULT);
|
|
|
|
g_assert_cmpint (dbus_message_get_type (reply), ==, DBUS_MESSAGE_TYPE_ERROR);
|
|
g_assert_cmpstr (dbus_message_get_error_name (reply), ==,
|
|
DBUS_ERROR_MATCH_RULE_INVALID);
|
|
|
|
dbus_clear_message (&reply);
|
|
dbus_clear_message (&m);
|
|
|
|
/* We did not become a monitor, so we can still call methods. */
|
|
|
|
m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
|
|
DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetId");
|
|
|
|
if (m == NULL)
|
|
g_error ("OOM");
|
|
|
|
reply = test_main_context_call_and_wait (f->ctx, f->monitor, m,
|
|
DBUS_TIMEOUT_USE_DEFAULT);
|
|
|
|
if (dbus_set_error_from_message (&f->e, reply))
|
|
g_error ("%s: %s", f->e.name, f->e.message);
|
|
|
|
ok = dbus_message_get_args (reply, &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_clear_message (&reply);
|
|
dbus_clear_message (&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);
|
|
|
|
if (!dbus_connection_add_filter (f->recipient, recipient_enqueue_filter,
|
|
f, NULL))
|
|
g_error ("OOM");
|
|
f->recipient_enqueue_filter_added = TRUE;
|
|
|
|
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);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotBroadcast",
|
|
"CannotBroadcast");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotBroadcast2",
|
|
"CannotBroadcast2");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* these two will go through: we use them as an indirect way to assert that
|
|
* the recipient has not received anything earlier */
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotUnicast",
|
|
"CannotUnicast");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotUnicast2",
|
|
"CannotUnicast2");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
while (g_queue_get_length (&f->monitored) < 12)
|
|
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);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotBroadcast",
|
|
"CannotBroadcast", "", 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.CannotBroadcast2",
|
|
"CannotBroadcast2", "", 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.CannotUnicast",
|
|
"CannotUnicast", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotUnicast2",
|
|
"CannotUnicast2", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
|
|
/* the intended recipient only received the ones that were on the interface
|
|
* where broadcasts are allowed */
|
|
|
|
while (g_queue_get_length (&f->received) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->received);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotUnicast",
|
|
"CannotUnicast", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->received);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotUnicast2",
|
|
"CannotUnicast2", "", NULL);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->received);
|
|
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;
|
|
|
|
if (!dbus_connection_add_filter (f->recipient, recipient_enqueue_filter,
|
|
f, NULL))
|
|
g_error ("OOM");
|
|
f->recipient_enqueue_filter_added = TRUE;
|
|
|
|
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);
|
|
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotUnicast",
|
|
"CannotUnicast");
|
|
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.CannotUnicast2",
|
|
"CannotUnicast2");
|
|
if (!dbus_message_set_destination (m, f->recipient_name))
|
|
g_error ("OOM");
|
|
dbus_connection_send (f->sender, m, NULL);
|
|
dbus_message_unref (m);
|
|
|
|
/* these two will go through: we use them as an indirect way to assert that
|
|
* the recipient has not received anything earlier */
|
|
m = dbus_message_new_signal ("/foo", "com.example.CannotBroadcast",
|
|
"CannotBroadcast");
|
|
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.CannotBroadcast2",
|
|
"CannotBroadcast2");
|
|
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) < 12)
|
|
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);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotUnicast",
|
|
"CannotUnicast", "", 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.CannotUnicast2",
|
|
"CannotUnicast2", "", 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.CannotBroadcast",
|
|
"CannotBroadcast", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotBroadcast2",
|
|
"CannotBroadcast2", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->monitored);
|
|
g_assert (m == NULL);
|
|
|
|
/* the intended recipient only received the ones that were on the interface
|
|
* where unicasts are allowed */
|
|
|
|
while (g_queue_get_length (&f->received) < 2)
|
|
test_main_context_iterate (f->ctx, TRUE);
|
|
|
|
m = g_queue_pop_head (&f->received);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotBroadcast",
|
|
"CannotBroadcast", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->received);
|
|
assert_signal (m, f->sender_name, "/foo", "com.example.CannotBroadcast2",
|
|
"CannotBroadcast2", "", f->recipient_name);
|
|
dbus_message_unref (m);
|
|
|
|
m = g_queue_pop_head (&f->received);
|
|
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)
|
|
{
|
|
GList *link;
|
|
|
|
dbus_error_free (&f->e);
|
|
g_clear_error (&f->ge);
|
|
|
|
if (f->monitor != NULL)
|
|
{
|
|
dbus_connection_remove_filter (f->monitor, monitor_filter, f);
|
|
test_connection_shutdown (f->ctx, f->monitor);
|
|
dbus_connection_close (f->monitor);
|
|
dbus_connection_unref (f->monitor);
|
|
f->monitor = NULL;
|
|
}
|
|
|
|
if (f->sender != NULL)
|
|
{
|
|
test_connection_shutdown (f->ctx, f->sender);
|
|
dbus_connection_close (f->sender);
|
|
dbus_connection_unref (f->sender);
|
|
f->sender = NULL;
|
|
}
|
|
|
|
if (f->recipient != NULL)
|
|
{
|
|
dbus_connection_remove_filter (f->recipient, recipient_check_filter, f);
|
|
if (f->recipient_enqueue_filter_added)
|
|
dbus_connection_remove_filter (f->recipient, recipient_enqueue_filter,
|
|
f);
|
|
|
|
test_connection_shutdown (f->ctx, f->recipient);
|
|
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);
|
|
test_connection_shutdown (f->ctx, f->systemd);
|
|
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);
|
|
test_connection_shutdown (f->ctx, f->activated);
|
|
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);
|
|
|
|
for (link = f->monitored.head; link != NULL; link = link->next)
|
|
dbus_message_unref (link->data);
|
|
|
|
g_queue_clear (&f->monitored);
|
|
|
|
for (link = f->received.head; link != NULL; link = link->next)
|
|
dbus_message_unref (link->data);
|
|
|
|
g_queue_clear (&f->received);
|
|
|
|
g_free (f->address);
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char **argv)
|
|
{
|
|
int ret;
|
|
|
|
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
|
|
|
|
ret = g_test_run ();
|
|
dbus_shutdown ();
|
|
return ret;
|
|
}
|