mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2025-12-26 08:40:08 +01:00
A variety of system components have migrated from legacy init into DBus service activation. Many of these system components "daemonize", which involves forking. The DBus activation system treated an exit as an activation failure, assuming that the child process which grabbed the DBus name didn't run first. While we're in here, also differentiate in this code path between the servicehelper (system) versus direct activation (session) paths. In the session activation path our error message mentioned a helper process which was confusing, since none was involved. Based on a patch and debugging research from Ray Strode <rstrode@redhat.com>
489 lines
13 KiB
C
489 lines
13 KiB
C
|
|
#include "test-utils.h"
|
|
#include <unistd.h>
|
|
|
|
static DBusLoop *loop;
|
|
static dbus_bool_t already_quit = FALSE;
|
|
static dbus_bool_t hello_from_self_reply_received = FALSE;
|
|
|
|
static void
|
|
quit (void)
|
|
{
|
|
if (!already_quit)
|
|
{
|
|
_dbus_loop_quit (loop);
|
|
already_quit = TRUE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
die (const char *message)
|
|
{
|
|
fprintf (stderr, "*** test-service: %s", message);
|
|
exit (1);
|
|
}
|
|
|
|
static void
|
|
check_hello_from_self_reply (DBusPendingCall *pcall,
|
|
void *user_data)
|
|
{
|
|
DBusMessage *reply;
|
|
DBusMessage *echo_message, *echo_reply = NULL;
|
|
DBusError error;
|
|
DBusConnection *connection;
|
|
|
|
int type;
|
|
|
|
dbus_error_init (&error);
|
|
|
|
connection = dbus_bus_get (DBUS_BUS_STARTER, &error);
|
|
if (connection == NULL)
|
|
{
|
|
fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n",
|
|
error.message);
|
|
dbus_error_free (&error);
|
|
die("no memory");
|
|
}
|
|
|
|
|
|
echo_message = (DBusMessage *)user_data;
|
|
|
|
reply = dbus_pending_call_steal_reply (pcall);
|
|
|
|
type = dbus_message_get_type (reply);
|
|
|
|
if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN)
|
|
{
|
|
const char *s;
|
|
printf ("Reply from HelloFromSelf received\n");
|
|
|
|
if (!dbus_message_get_args (echo_message,
|
|
&error,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID))
|
|
{
|
|
echo_reply = dbus_message_new_error (echo_message,
|
|
error.name,
|
|
error.message);
|
|
|
|
if (echo_reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
}
|
|
else
|
|
{
|
|
echo_reply = dbus_message_new_method_return (echo_message);
|
|
if (echo_reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_message_append_args (echo_reply,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID))
|
|
die ("No memory");
|
|
}
|
|
|
|
if (!dbus_connection_send (connection, echo_reply, NULL))
|
|
die ("No memory\n");
|
|
|
|
dbus_message_unref (echo_reply);
|
|
}
|
|
else if (type == DBUS_MESSAGE_TYPE_ERROR)
|
|
{
|
|
dbus_set_error_from_message (&error, reply);
|
|
printf ("Error type in reply: %s\n", error.message);
|
|
|
|
if (strcmp (error.name, DBUS_ERROR_NO_MEMORY) != 0)
|
|
{
|
|
echo_reply = dbus_message_new_error (echo_reply,
|
|
error.name,
|
|
error.message);
|
|
|
|
if (echo_reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_connection_send (connection, echo_reply, NULL))
|
|
die ("No memory\n");
|
|
|
|
dbus_message_unref (echo_reply);
|
|
}
|
|
dbus_error_free (&error);
|
|
}
|
|
else
|
|
_dbus_assert_not_reached ("Unexpected message received\n");
|
|
|
|
hello_from_self_reply_received = TRUE;
|
|
|
|
dbus_message_unref (reply);
|
|
dbus_message_unref (echo_message);
|
|
dbus_pending_call_unref (pcall);
|
|
dbus_connection_unref (connection);
|
|
}
|
|
|
|
static DBusHandlerResult
|
|
handle_run_hello_from_self (DBusConnection *connection,
|
|
DBusMessage *message)
|
|
{
|
|
DBusError error;
|
|
DBusMessage *reply, *self_message;
|
|
DBusPendingCall *pcall;
|
|
char *s;
|
|
|
|
_dbus_verbose ("sending reply to Echo method\n");
|
|
|
|
dbus_error_init (&error);
|
|
|
|
if (!dbus_message_get_args (message,
|
|
&error,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID))
|
|
{
|
|
reply = dbus_message_new_error (message,
|
|
error.name,
|
|
error.message);
|
|
|
|
if (reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_connection_send (connection, reply, NULL))
|
|
die ("No memory\n");
|
|
|
|
dbus_message_unref (reply);
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
printf ("Sending HelloFromSelf\n");
|
|
|
|
_dbus_verbose ("*** Sending message to self\n");
|
|
self_message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService",
|
|
"/org/freedesktop/TestSuite",
|
|
"org.freedesktop.TestSuite",
|
|
"HelloFromSelf");
|
|
|
|
if (self_message == NULL)
|
|
die ("No memory");
|
|
|
|
if (!dbus_connection_send_with_reply (connection, self_message, &pcall, -1))
|
|
die("No memory");
|
|
|
|
dbus_message_ref (message);
|
|
if (!dbus_pending_call_set_notify (pcall, check_hello_from_self_reply, (void *)message, NULL))
|
|
die("No memory");
|
|
|
|
printf ("Sent HelloFromSelf\n");
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
|
|
static DBusHandlerResult
|
|
handle_echo (DBusConnection *connection,
|
|
DBusMessage *message)
|
|
{
|
|
DBusError error;
|
|
DBusMessage *reply;
|
|
char *s;
|
|
|
|
_dbus_verbose ("sending reply to Echo method\n");
|
|
|
|
dbus_error_init (&error);
|
|
|
|
if (!dbus_message_get_args (message,
|
|
&error,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID))
|
|
{
|
|
reply = dbus_message_new_error (message,
|
|
error.name,
|
|
error.message);
|
|
|
|
if (reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_connection_send (connection, reply, NULL))
|
|
die ("No memory\n");
|
|
|
|
dbus_message_unref (reply);
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
reply = dbus_message_new_method_return (message);
|
|
if (reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_message_append_args (reply,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID))
|
|
die ("No memory");
|
|
|
|
if (!dbus_connection_send (connection, reply, NULL))
|
|
die ("No memory\n");
|
|
|
|
fprintf (stderr, "Echo service echoed string: \"%s\"\n", s);
|
|
|
|
dbus_message_unref (reply);
|
|
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
|
|
static DBusHandlerResult
|
|
handle_delay_echo (DBusConnection *connection,
|
|
DBusMessage *message)
|
|
{
|
|
DBusError error;
|
|
DBusMessage *reply;
|
|
char *s;
|
|
|
|
_dbus_verbose ("sleeping for a short time\n");
|
|
|
|
usleep (50000);
|
|
|
|
_dbus_verbose ("sending reply to DelayEcho method\n");
|
|
|
|
dbus_error_init (&error);
|
|
|
|
if (!dbus_message_get_args (message,
|
|
&error,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID))
|
|
{
|
|
reply = dbus_message_new_error (message,
|
|
error.name,
|
|
error.message);
|
|
|
|
if (reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_connection_send (connection, reply, NULL))
|
|
die ("No memory\n");
|
|
|
|
dbus_message_unref (reply);
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
reply = dbus_message_new_method_return (message);
|
|
if (reply == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_message_append_args (reply,
|
|
DBUS_TYPE_STRING, &s,
|
|
DBUS_TYPE_INVALID))
|
|
die ("No memory");
|
|
|
|
if (!dbus_connection_send (connection, reply, NULL))
|
|
die ("No memory\n");
|
|
|
|
fprintf (stderr, "DelayEcho service echoed string: \"%s\"\n", s);
|
|
|
|
dbus_message_unref (reply);
|
|
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
|
|
|
|
static void
|
|
path_unregistered_func (DBusConnection *connection,
|
|
void *user_data)
|
|
{
|
|
/* connection was finalized */
|
|
}
|
|
|
|
static DBusHandlerResult
|
|
path_message_func (DBusConnection *connection,
|
|
DBusMessage *message,
|
|
void *user_data)
|
|
{
|
|
if (dbus_message_is_method_call (message,
|
|
"org.freedesktop.TestSuite",
|
|
"Echo"))
|
|
return handle_echo (connection, message);
|
|
else if (dbus_message_is_method_call (message,
|
|
"org.freedesktop.TestSuite",
|
|
"DelayEcho"))
|
|
return handle_delay_echo (connection, message);
|
|
else if (dbus_message_is_method_call (message,
|
|
"org.freedesktop.TestSuite",
|
|
"Exit"))
|
|
{
|
|
quit ();
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
else if (dbus_message_is_method_call (message,
|
|
"org.freedesktop.TestSuite",
|
|
"EmitFoo"))
|
|
{
|
|
/* Emit the Foo signal */
|
|
DBusMessage *signal;
|
|
double v_DOUBLE;
|
|
|
|
_dbus_verbose ("emitting signal Foo\n");
|
|
|
|
signal = dbus_message_new_signal ("/org/freedesktop/TestSuite",
|
|
"org.freedesktop.TestSuite",
|
|
"Foo");
|
|
if (signal == NULL)
|
|
die ("No memory\n");
|
|
|
|
v_DOUBLE = 42.6;
|
|
if (!dbus_message_append_args (signal,
|
|
DBUS_TYPE_DOUBLE, &v_DOUBLE,
|
|
DBUS_TYPE_INVALID))
|
|
die ("No memory");
|
|
|
|
if (!dbus_connection_send (connection, signal, NULL))
|
|
die ("No memory\n");
|
|
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
|
|
else if (dbus_message_is_method_call (message,
|
|
"org.freedesktop.TestSuite",
|
|
"RunHelloFromSelf"))
|
|
{
|
|
return handle_run_hello_from_self (connection, message);
|
|
}
|
|
else if (dbus_message_is_method_call (message,
|
|
"org.freedesktop.TestSuite",
|
|
"HelloFromSelf"))
|
|
{
|
|
DBusMessage *reply;
|
|
printf ("Received the HelloFromSelf message\n");
|
|
|
|
reply = dbus_message_new_method_return (message);
|
|
if (reply == NULL)
|
|
die ("No memory");
|
|
|
|
if (!dbus_connection_send (connection, reply, NULL))
|
|
die ("No memory");
|
|
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
else
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
static DBusObjectPathVTable
|
|
echo_vtable = {
|
|
path_unregistered_func,
|
|
path_message_func,
|
|
NULL,
|
|
};
|
|
|
|
|
|
static const char* echo_path = "/org/freedesktop/TestSuite" ;
|
|
|
|
static DBusHandlerResult
|
|
filter_func (DBusConnection *connection,
|
|
DBusMessage *message,
|
|
void *user_data)
|
|
{
|
|
if (dbus_message_is_signal (message,
|
|
DBUS_INTERFACE_LOCAL,
|
|
"Disconnected"))
|
|
{
|
|
quit ();
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
else
|
|
{
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char **argv)
|
|
{
|
|
DBusError error;
|
|
int result;
|
|
DBusConnection *connection;
|
|
const char *name;
|
|
dbus_bool_t do_fork;
|
|
|
|
if (argc != 3)
|
|
{
|
|
name = "org.freedesktop.DBus.TestSuiteEchoService";
|
|
do_fork = FALSE;
|
|
}
|
|
else
|
|
{
|
|
name = argv[1];
|
|
do_fork = strcmp (argv[2], "fork") == 0;
|
|
}
|
|
|
|
/* The bare minimum for simulating a program "daemonizing"; the intent
|
|
* is to test services which move from being legacy init scripts to
|
|
* activated services.
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=545267
|
|
*/
|
|
if (do_fork)
|
|
{
|
|
pid_t pid = fork ();
|
|
if (pid != 0)
|
|
exit (0);
|
|
sleep (1);
|
|
}
|
|
|
|
dbus_error_init (&error);
|
|
connection = dbus_bus_get (DBUS_BUS_STARTER, &error);
|
|
if (connection == NULL)
|
|
{
|
|
fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n",
|
|
error.message);
|
|
dbus_error_free (&error);
|
|
return 1;
|
|
}
|
|
|
|
loop = _dbus_loop_new ();
|
|
if (loop == NULL)
|
|
die ("No memory\n");
|
|
|
|
if (!test_connection_setup (loop, connection))
|
|
die ("No memory\n");
|
|
|
|
if (!dbus_connection_add_filter (connection,
|
|
filter_func, NULL, NULL))
|
|
die ("No memory");
|
|
|
|
if (!dbus_connection_register_object_path (connection,
|
|
echo_path,
|
|
&echo_vtable,
|
|
(void*) 0xdeadbeef))
|
|
die ("No memory");
|
|
|
|
{
|
|
void *d;
|
|
if (!dbus_connection_get_object_path_data (connection, echo_path, &d))
|
|
die ("No memory");
|
|
if (d != (void*) 0xdeadbeef)
|
|
die ("dbus_connection_get_object_path_data() doesn't seem to work right\n");
|
|
}
|
|
|
|
result = dbus_bus_request_name (connection, name,
|
|
0, &error);
|
|
if (dbus_error_is_set (&error))
|
|
{
|
|
fprintf (stderr, "Error %s\n", error.message);
|
|
_dbus_verbose ("*** Failed to acquire service: %s\n",
|
|
error.message);
|
|
dbus_error_free (&error);
|
|
exit (1);
|
|
}
|
|
|
|
_dbus_verbose ("*** Test service entering main loop\n");
|
|
_dbus_loop_run (loop);
|
|
|
|
test_connection_shutdown (loop, connection);
|
|
|
|
dbus_connection_remove_filter (connection, filter_func, NULL);
|
|
|
|
dbus_connection_unref (connection);
|
|
|
|
_dbus_loop_unref (loop);
|
|
loop = NULL;
|
|
|
|
dbus_shutdown ();
|
|
|
|
_dbus_verbose ("*** Test service exiting\n");
|
|
|
|
return 0;
|
|
}
|