Bug 623142 – Ensure ::new-connection runs before processing D-Bus messages

Without this guarantee, peer-to-peer connections are not very
useful. However, with this guarantee it's possible to export objects
in a handler for the GDBusServer::new-connection signal.

There are two caveats with this patch

 - it won't work on message bus connections
 - we don't queue up messages to be written

that can be addresses later if needed.

https://bugzilla.gnome.org/show_bug.cgi?id=623142

Signed-off-by: David Zeuthen <davidz@redhat.com>
This commit is contained in:
David Zeuthen
2010-06-30 11:43:42 -04:00
parent 137ae2413c
commit 038d03cd08
9 changed files with 316 additions and 8 deletions

View File

@@ -732,6 +732,192 @@ test_peer (void)
/* ---------------------------------------------------------------------------------------------------- */
typedef struct
{
GDBusServer *server;
GMainContext *context;
GMainLoop *loop;
GList *connections;
} DmpData;
static void
dmp_data_free (DmpData *data)
{
g_main_loop_unref (data->loop);
g_main_context_unref (data->context);
g_object_unref (data->server);
g_list_foreach (data->connections, (GFunc) g_object_unref, NULL);
g_list_free (data->connections);
g_free (data);
}
static void
dmp_on_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
//DmpData *data = user_data;
gint32 first;
gint32 second;
g_variant_get (parameters,
"(ii)",
&first,
&second);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(i)", first + second));
}
static const GDBusInterfaceVTable dmp_interface_vtable =
{
dmp_on_method_call,
NULL, /* get_property */
NULL /* set_property */
};
/* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
static void
dmp_on_new_connection (GDBusServer *server,
GDBusConnection *connection,
gpointer user_data)
{
DmpData *data = user_data;
GDBusNodeInfo *node;
GError *error;
/* accept the connection */
data->connections = g_list_prepend (data->connections, g_object_ref (connection));
error = NULL;
node = g_dbus_node_info_new_for_xml ("<node>"
" <interface name='org.gtk.GDBus.DmpInterface'>"
" <method name='AddPair'>"
" <arg type='i' name='first' direction='in'/>"
" <arg type='i' name='second' direction='in'/>"
" <arg type='i' name='sum' direction='out'/>"
" </method>"
" </interface>"
"</node>",
&error);
g_assert_no_error (error);
/* sleep 100ms before exporting an object - this is to test that
* G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING really works
* (GDBusServer uses this feature).
*/
usleep (100 * 1000);
/* export an object */
error = NULL;
g_dbus_connection_register_object (connection,
"/dmp/test",
node->interfaces[0],
&dmp_interface_vtable,
data,
NULL,
&error);
//g_dbus_node_info_unref (node);
}
static gpointer
dmp_thread_func (gpointer user_data)
{
DmpData *data = user_data;
GError *error;
gchar *guid;
data->context = g_main_context_new ();
g_main_context_push_thread_default (data->context);
error = NULL;
guid = g_dbus_generate_guid ();
data->server = g_dbus_server_new_sync ("nonce-tcp:",
G_DBUS_SERVER_FLAGS_NONE,
guid,
NULL, /* GDBusAuthObserver */
NULL, /* GCancellable */
&error);
g_assert_no_error (error);
g_signal_connect (data->server,
"new-connection",
G_CALLBACK (dmp_on_new_connection),
data);
g_dbus_server_start (data->server);
data->loop = g_main_loop_new (data->context, FALSE);
g_main_loop_run (data->loop);
g_main_context_pop_thread_default (data->context);
g_free (guid);
return NULL;
}
static void
delayed_message_processing (void)
{
GError *error;
DmpData *data;
GThread *service_thread;
guint n;
data = g_new0 (DmpData, 1);
error = NULL;
service_thread = g_thread_create (dmp_thread_func,
data,
TRUE,
&error);
while (data->server == NULL || !g_dbus_server_is_active (data->server))
g_thread_yield ();
for (n = 0; n < 5; n++)
{
GDBusConnection *c;
GVariant *res;
gint32 val;
error = NULL;
c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data->server),
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
NULL, /* GDBusAuthObserver */
NULL, /* GCancellable */
&error);
g_assert_no_error (error);
error = NULL;
res = g_dbus_connection_call_sync (c,
NULL, /* bus name */
"/dmp/test",
"org.gtk.GDBus.DmpInterface",
"AddPair",
g_variant_new ("(ii)", 2, n),
G_VARIANT_TYPE ("(i)"),
G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout_msec */
NULL, /* GCancellable */
&error);
g_assert_no_error (error);
g_variant_get (res, "(i)", &val);
g_assert_cmpint (val, ==, 2 + n);
g_variant_unref (res);
g_object_unref (c);
}
g_main_loop_quit (data->loop);
g_thread_join (service_thread);
dmp_data_free (data);
}
/* ---------------------------------------------------------------------------------------------------- */
int
main (int argc,
char *argv[])
@@ -753,6 +939,7 @@ main (int argc,
loop = g_main_loop_new (NULL, FALSE);
g_test_add_func ("/gdbus/peer-to-peer", test_peer);
g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing);
ret = g_test_run();