1 /* GLib testing framework examples and tests
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: David Zeuthen <davidz@redhat.com>
30 #include <sys/types.h>
36 #include <glib/gstdio.h>
38 #include <gio/gnetworking.h>
39 #include <gio/gunixsocketaddress.h>
40 #include <gio/gunixfdlist.h>
43 #include <gio/gunixconnection.h>
47 #if (defined(__linux__) || \
48 defined(__FreeBSD__) || \
49 defined(__FreeBSD_kernel__) || \
51 #define SHOULD_HAVE_CREDENTIALS_PASSING
54 #include "gdbus-tests.h"
56 #include "gdbus-object-manager-example/gdbus-example-objectmanager-generated.h"
59 static gboolean is_unix = TRUE;
61 static gboolean is_unix = FALSE;
64 static gchar *tmp_address = NULL;
65 static gchar *test_guid = NULL;
66 static GMutex service_loop_lock;
67 static GCond service_loop_cond;
68 static GMainLoop *service_loop = NULL;
69 static GDBusServer *server = NULL;
70 static GMainLoop *loop = NULL;
72 /* ---------------------------------------------------------------------------------------------------- */
73 /* Test that peer-to-peer connections work */
74 /* ---------------------------------------------------------------------------------------------------- */
79 gboolean accept_connection;
80 gint num_connection_attempts;
81 GPtrArray *current_connections;
82 guint num_method_calls;
83 gboolean signal_received;
86 static const gchar *test_interface_introspection_xml =
88 " <interface name='org.gtk.GDBus.PeerTestInterface'>"
89 " <method name='HelloPeer'>"
90 " <arg type='s' name='greeting' direction='in'/>"
91 " <arg type='s' name='response' direction='out'/>"
93 " <method name='EmitSignal'/>"
94 " <method name='EmitSignalWithNameSet'/>"
95 " <method name='OpenFile'>"
96 " <arg type='s' name='path' direction='in'/>"
98 " <signal name='PeerSignal'>"
99 " <arg type='s' name='a_string'/>"
101 " <property type='s' name='PeerProperty' access='read'/>"
104 static GDBusInterfaceInfo *test_interface_introspection_data = NULL;
107 test_interface_method_call (GDBusConnection *connection,
109 const gchar *object_path,
110 const gchar *interface_name,
111 const gchar *method_name,
112 GVariant *parameters,
113 GDBusMethodInvocation *invocation,
116 PeerData *data = user_data;
117 const GDBusMethodInfo *info;
119 data->num_method_calls++;
121 g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
122 g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
124 info = g_dbus_method_invocation_get_method_info (invocation);
125 g_assert_cmpstr (info->name, ==, method_name);
127 if (g_strcmp0 (method_name, "HelloPeer") == 0)
129 const gchar *greeting;
132 g_variant_get (parameters, "(&s)", &greeting);
134 response = g_strdup_printf ("You greeted me with '%s'.",
136 g_dbus_method_invocation_return_value (invocation,
137 g_variant_new ("(s)", response));
140 else if (g_strcmp0 (method_name, "EmitSignal") == 0)
145 g_dbus_connection_emit_signal (connection,
147 "/org/gtk/GDBus/PeerTestObject",
148 "org.gtk.GDBus.PeerTestInterface",
152 g_assert_no_error (error);
153 g_dbus_method_invocation_return_value (invocation, NULL);
155 else if (g_strcmp0 (method_name, "EmitSignalWithNameSet") == 0)
159 GDBusMessage *message;
161 message = g_dbus_message_new_signal ("/org/gtk/GDBus/PeerTestObject",
162 "org.gtk.GDBus.PeerTestInterface",
163 "PeerSignalWithNameSet");
164 g_dbus_message_set_sender (message, ":1.42");
167 ret = g_dbus_connection_send_message (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error);
168 g_assert_no_error (error);
170 g_object_unref (message);
172 g_dbus_method_invocation_return_value (invocation, NULL);
174 else if (g_strcmp0 (method_name, "OpenFile") == 0)
181 GUnixFDList *fd_list;
183 g_variant_get (parameters, "(&s)", &path);
185 fd_list = g_unix_fd_list_new ();
189 fd = g_open (path, O_RDONLY, 0);
191 g_unix_fd_list_append (fd_list, fd, &error);
192 g_assert_no_error (error);
195 reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
196 g_dbus_message_set_unix_fd_list (reply, fd_list);
197 g_object_unref (fd_list);
198 g_object_unref (invocation);
201 g_dbus_connection_send_message (connection,
203 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
204 NULL, /* out_serial */
206 g_assert_no_error (error);
207 g_object_unref (reply);
209 g_dbus_method_invocation_return_dbus_error (invocation,
210 "org.gtk.GDBus.NotOnUnix",
211 "Your OS does not support file descriptor passing");
216 g_assert_not_reached ();
221 test_interface_get_property (GDBusConnection *connection,
223 const gchar *object_path,
224 const gchar *interface_name,
225 const gchar *property_name,
229 g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
230 g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
231 g_assert_cmpstr (property_name, ==, "PeerProperty");
233 return g_variant_new_string ("ThePropertyValue");
237 static const GDBusInterfaceVTable test_interface_vtable =
239 test_interface_method_call,
240 test_interface_get_property,
241 NULL /* set_property */
245 on_proxy_signal_received (GDBusProxy *proxy,
248 GVariant *parameters,
251 PeerData *data = user_data;
253 data->signal_received = TRUE;
255 g_assert (sender_name == NULL);
256 g_assert_cmpstr (signal_name, ==, "PeerSignal");
257 g_main_loop_quit (loop);
261 on_proxy_signal_received_with_name_set (GDBusProxy *proxy,
264 GVariant *parameters,
267 PeerData *data = user_data;
269 data->signal_received = TRUE;
271 g_assert_cmpstr (sender_name, ==, ":1.42");
272 g_assert_cmpstr (signal_name, ==, "PeerSignalWithNameSet");
273 g_main_loop_quit (loop);
276 /* ---------------------------------------------------------------------------------------------------- */
279 on_authorize_authenticated_peer (GDBusAuthObserver *observer,
281 GCredentials *credentials,
284 PeerData *data = user_data;
287 data->num_connection_attempts++;
290 if (!data->accept_connection)
293 g_main_loop_quit (loop);
299 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
301 on_new_connection (GDBusServer *server,
302 GDBusConnection *connection,
305 PeerData *data = user_data;
309 //g_print ("Client connected.\n"
310 // "Negotiated capabilities: unix-fd-passing=%d\n",
311 // g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
313 g_ptr_array_add (data->current_connections, g_object_ref (connection));
315 #ifdef SHOULD_HAVE_CREDENTIALS_PASSING
317 GCredentials *credentials;
319 credentials = g_dbus_connection_get_peer_credentials (connection);
321 g_assert (credentials != NULL);
322 g_assert_cmpuint (g_credentials_get_unix_user (credentials, NULL), ==,
324 g_assert_cmpuint (g_credentials_get_unix_pid (credentials, NULL), ==,
329 /* export object on the newly established connection */
331 reg_id = g_dbus_connection_register_object (connection,
332 "/org/gtk/GDBus/PeerTestObject",
333 test_interface_introspection_data,
334 &test_interface_vtable,
336 NULL, /* GDestroyNotify for data */
338 g_assert_no_error (error);
339 g_assert (reg_id > 0);
341 g_main_loop_quit (loop);
347 create_service_loop (GMainContext *service_context)
349 g_assert (service_loop == NULL);
350 g_mutex_lock (&service_loop_lock);
351 service_loop = g_main_loop_new (service_context, FALSE);
352 g_cond_broadcast (&service_loop_cond);
353 g_mutex_unlock (&service_loop_lock);
357 teardown_service_loop (void)
359 g_mutex_lock (&service_loop_lock);
360 g_clear_pointer (&service_loop, g_main_loop_unref);
361 g_mutex_unlock (&service_loop_lock);
365 await_service_loop (void)
367 g_mutex_lock (&service_loop_lock);
368 while (service_loop == NULL)
369 g_cond_wait (&service_loop_cond, &service_loop_lock);
370 g_mutex_unlock (&service_loop_lock);
374 service_thread_func (gpointer user_data)
376 PeerData *data = user_data;
377 GMainContext *service_context;
378 GDBusAuthObserver *observer, *o;
384 service_context = g_main_context_new ();
385 g_main_context_push_thread_default (service_context);
388 observer = g_dbus_auth_observer_new ();
389 server = g_dbus_server_new_sync (tmp_address,
390 G_DBUS_SERVER_FLAGS_NONE,
393 NULL, /* cancellable */
395 g_assert_no_error (error);
397 g_signal_connect (server,
399 G_CALLBACK (on_new_connection),
401 g_signal_connect (observer,
402 "authorize-authenticated-peer",
403 G_CALLBACK (on_authorize_authenticated_peer),
406 g_assert_cmpint (g_dbus_server_get_flags (server), ==, G_DBUS_SERVER_FLAGS_NONE);
407 g_assert_cmpstr (g_dbus_server_get_guid (server), ==, test_guid);
408 g_object_get (server,
413 "authentication-observer", &o,
415 g_assert_cmpint (f, ==, G_DBUS_SERVER_FLAGS_NONE);
416 g_assert_cmpstr (a, ==, tmp_address);
417 g_assert_cmpstr (g, ==, test_guid);
419 g_assert (o == observer);
424 g_object_unref (observer);
426 g_dbus_server_start (server);
428 create_service_loop (service_context);
429 g_main_loop_run (service_loop);
431 g_main_context_pop_thread_default (service_context);
433 teardown_service_loop ();
434 g_main_context_unref (service_context);
436 /* test code specifically unrefs the server - see below */
437 g_assert (server == NULL);
444 on_incoming_connection (GSocketService *service,
445 GSocketConnection *socket_connection,
446 GObject *source_object,
449 PeerData *data = user_data;
451 if (data->accept_connection)
455 GDBusConnection *connection;
458 connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
460 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
461 NULL, /* cancellable */
463 g_assert_no_error (error);
465 g_ptr_array_add (data->current_connections, connection);
467 /* export object on the newly established connection */
469 reg_id = g_dbus_connection_register_object (connection,
470 "/org/gtk/GDBus/PeerTestObject",
471 &test_interface_introspection_data,
472 &test_interface_vtable,
474 NULL, /* GDestroyNotify for data */
476 g_assert_no_error (error);
477 g_assert (reg_id > 0);
482 /* don't do anything */
485 data->num_connection_attempts++;
487 g_main_loop_quit (loop);
489 /* stops other signal handlers from being invoked */
494 service_thread_func (gpointer data)
496 GMainContext *service_context;
498 GSocketAddress *address;
501 service_context = g_main_context_new ();
502 g_main_context_push_thread_default (service_context);
504 socket_path = g_strdup_printf ("/tmp/gdbus-test-pid-%d", getpid ());
505 address = g_unix_socket_address_new (socket_path);
507 service = g_socket_service_new ();
509 g_socket_listener_add_address (G_SOCKET_LISTENER (service),
511 G_SOCKET_TYPE_STREAM,
512 G_SOCKET_PROTOCOL_DEFAULT,
513 NULL, /* source_object */
514 NULL, /* effective_address */
516 g_assert_no_error (error);
517 g_signal_connect (service,
519 G_CALLBACK (on_incoming_connection),
521 g_socket_service_start (service);
523 create_service_loop (service_context);
524 g_main_loop_run (service_loop);
526 g_main_context_pop_thread_default (service_context);
528 teardown_service_loop ();
529 g_main_context_unref (service_context);
531 g_object_unref (address);
532 g_free (socket_path);
537 /* ---------------------------------------------------------------------------------------------------- */
541 check_connection (gpointer user_data)
543 PeerData *data = user_data;
546 for (n = 0; n < data->current_connections->len; n++)
551 c = G_DBUS_CONNECTION (data->current_connections->pdata[n]);
552 stream = g_dbus_connection_get_stream (c);
554 g_debug ("In check_connection for %d: connection %p, stream %p", n, c, stream);
555 g_debug ("closed = %d", g_io_stream_is_closed (stream));
558 socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
559 g_debug ("socket_closed = %d", g_socket_is_closed (socket));
560 g_debug ("socket_condition_check = %d", g_socket_condition_check (socket, G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP));
566 num_read = g_input_stream_read (g_io_stream_get_input_stream (stream),
573 g_debug ("error: %s", error->message);
574 g_error_free (error);
578 g_debug ("no error, read %d bytes", (gint) num_read);
586 on_do_disconnect_in_idle (gpointer data)
588 GDBusConnection *c = G_DBUS_CONNECTION (data);
589 g_debug ("GDC %p has ref_count %d", c, G_OBJECT (c)->ref_count);
590 g_dbus_connection_disconnect (c);
598 read_all_from_fd (gint fd, gsize *out_len, GError **error)
604 str = g_string_new (NULL);
608 num_read = read (fd, buf, sizeof (buf));
611 if (errno == EAGAIN || errno == EWOULDBLOCK)
615 g_io_error_from_errno (errno),
616 "Failed reading %d bytes into offset %d: %s",
622 else if (num_read > 0)
624 g_string_append_len (str, buf, num_read);
626 else if (num_read == 0)
635 return g_string_free (str, FALSE);
640 g_string_free (str, TRUE);
656 GThread *service_thread;
657 gulong signal_handler_id;
659 memset (&data, '\0', sizeof (PeerData));
660 data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
662 /* first try to connect when there is no server */
664 c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" :
665 /* NOTE: Even if something is listening on port 12345 the connection
666 * will fail because the nonce file doesn't exist */
667 "nonce-tcp:host=localhost,port=12345,noncefile=this-does-not-exist-gdbus",
668 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
669 NULL, /* GDBusAuthObserver */
670 NULL, /* cancellable */
672 _g_assert_error_domain (error, G_IO_ERROR);
673 g_assert (!g_dbus_error_is_remote_error (error));
674 g_clear_error (&error);
675 g_assert (c == NULL);
677 /* bring up a server - we run the server in a different thread to avoid deadlocks */
678 service_thread = g_thread_new ("test_peer",
681 await_service_loop ();
682 g_assert (server != NULL);
684 /* bring up a connection and accept it */
685 data.accept_connection = TRUE;
687 c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
688 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
689 NULL, /* GDBusAuthObserver */
690 NULL, /* cancellable */
692 g_assert_no_error (error);
693 g_assert (c != NULL);
694 while (data.current_connections->len < 1)
695 g_main_loop_run (loop);
696 g_assert_cmpint (data.current_connections->len, ==, 1);
697 g_assert_cmpint (data.num_connection_attempts, ==, 1);
698 g_assert (g_dbus_connection_get_unique_name (c) == NULL);
699 g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
701 /* check that we create a proxy, read properties, receive signals and invoke
702 * the HelloPeer() method. Since the server runs in another thread it's fine
703 * to use synchronous blocking API here.
706 proxy = g_dbus_proxy_new_sync (c,
707 G_DBUS_PROXY_FLAGS_NONE,
710 "/org/gtk/GDBus/PeerTestObject",
711 "org.gtk.GDBus.PeerTestInterface",
712 NULL, /* GCancellable */
714 g_assert_no_error (error);
715 g_assert (proxy != NULL);
717 value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
718 g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
720 /* try invoking a method */
722 result = g_dbus_proxy_call_sync (proxy,
724 g_variant_new ("(s)", "Hey Peer!"),
725 G_DBUS_CALL_FLAGS_NONE,
727 NULL, /* GCancellable */
729 g_assert_no_error (error);
730 g_variant_get (result, "(&s)", &s);
731 g_assert_cmpstr (s, ==, "You greeted me with 'Hey Peer!'.");
732 g_variant_unref (result);
733 g_assert_cmpint (data.num_method_calls, ==, 1);
735 /* make the other peer emit a signal - catch it */
736 signal_handler_id = g_signal_connect (proxy,
738 G_CALLBACK (on_proxy_signal_received),
740 g_assert (!data.signal_received);
741 g_dbus_proxy_call (proxy,
743 NULL, /* no arguments */
744 G_DBUS_CALL_FLAGS_NONE,
746 NULL, /* GCancellable */
747 NULL, /* GAsyncReadyCallback - we don't care about the result */
748 NULL); /* user_data */
749 g_main_loop_run (loop);
750 g_assert (data.signal_received);
751 g_assert_cmpint (data.num_method_calls, ==, 2);
752 g_signal_handler_disconnect (proxy, signal_handler_id);
754 /* Also ensure that messages with the sender header-field set gets
755 * delivered to the proxy - note that this doesn't really make sense
756 * e.g. names are meaning-less in a peer-to-peer case... but we
757 * support it because it makes sense in certain bridging
758 * applications - see e.g. #623815.
760 signal_handler_id = g_signal_connect (proxy,
762 G_CALLBACK (on_proxy_signal_received_with_name_set),
764 data.signal_received = FALSE;
765 g_dbus_proxy_call (proxy,
766 "EmitSignalWithNameSet",
767 NULL, /* no arguments */
768 G_DBUS_CALL_FLAGS_NONE,
770 NULL, /* GCancellable */
771 NULL, /* GAsyncReadyCallback - we don't care about the result */
772 NULL); /* user_data */
773 g_main_loop_run (loop);
774 g_assert (data.signal_received);
775 g_assert_cmpint (data.num_method_calls, ==, 3);
776 g_signal_handler_disconnect (proxy, signal_handler_id);
778 /* check for UNIX fd passing */
781 GDBusMessage *method_call_message;
782 GDBusMessage *method_reply_message;
783 GUnixFDList *fd_list;
789 const char *testfile = g_test_get_filename (G_TEST_DIST, "file.c", NULL);
791 method_call_message = g_dbus_message_new_method_call (NULL, /* name */
792 "/org/gtk/GDBus/PeerTestObject",
793 "org.gtk.GDBus.PeerTestInterface",
795 g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", testfile));
797 method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
799 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
801 NULL, /* out_serial */
802 NULL, /* cancellable */
804 g_assert_no_error (error);
805 g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
806 fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
807 g_assert (fd_list != NULL);
808 g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
810 fd = g_unix_fd_list_get (fd_list, 0, &error);
811 g_assert_no_error (error);
812 g_object_unref (method_call_message);
813 g_object_unref (method_reply_message);
817 buf = read_all_from_fd (fd, &len, &error);
818 g_assert_no_error (error);
819 g_assert (buf != NULL);
823 g_file_get_contents (testfile,
827 g_assert_no_error (error);
828 g_assert_cmpint (len, ==, len2);
829 g_assert (memcmp (buf, buf2, len) == 0);
835 result = g_dbus_proxy_call_sync (proxy,
837 g_variant_new ("(s)", "boo"),
838 G_DBUS_CALL_FLAGS_NONE,
840 NULL, /* GCancellable */
842 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
843 g_assert (result == NULL);
844 g_error_free (error);
845 #endif /* G_OS_UNIX */
847 /* Check that g_socket_get_credentials() work - this really should
848 * be in a GSocket-specific test suite but no such test suite exists
853 GCredentials *credentials;
854 socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (g_dbus_connection_get_stream (c)));
855 g_assert (G_IS_SOCKET (socket));
857 credentials = g_socket_get_credentials (socket, &error);
860 struct ucred *native_creds;
861 g_assert_no_error (error);
862 g_assert (G_IS_CREDENTIALS (credentials));
863 native_creds = g_credentials_get_native (credentials, G_CREDENTIALS_TYPE_LINUX_UCRED);
864 g_assert (native_creds != NULL);
865 g_assert (native_creds->uid == getuid ());
866 g_assert (native_creds->gid == getgid ());
867 g_assert (native_creds->pid == getpid ());
869 g_object_unref (credentials);
870 #elif defined (__OpenBSD__)
872 struct sockpeercred *native_creds;
873 g_assert_no_error (error);
874 g_assert (G_IS_CREDENTIALS (credentials));
875 native_creds = g_credentials_get_native (credentials, G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED);
876 g_assert (native_creds != NULL);
877 g_assert (native_creds->uid == getuid ());
878 g_assert (native_creds->gid == getgid ());
879 g_assert (native_creds->pid == getpid ());
881 g_object_unref (credentials);
883 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
884 g_assert (credentials == NULL);
889 /* bring up a connection - don't accept it - this should fail
891 data.accept_connection = FALSE;
893 c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
894 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
895 NULL, /* GDBusAuthObserver */
896 NULL, /* cancellable */
898 _g_assert_error_domain (error, G_IO_ERROR);
899 g_error_free (error);
900 g_assert (c2 == NULL);
903 /* TODO: THIS TEST DOESN'T WORK YET */
905 /* bring up a connection - accept it.. then disconnect from the client side - check
906 * that the server side gets the disconnect signal.
909 data.accept_connection = TRUE;
910 c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
911 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
912 NULL, /* GDBusAuthObserver */
913 NULL, /* cancellable */
915 g_assert_no_error (error);
916 g_assert (c2 != NULL);
917 g_assert (!g_dbus_connection_get_is_disconnected (c2));
918 while (data.num_connection_attempts < 3)
919 g_main_loop_run (loop);
920 g_assert_cmpint (data.current_connections->len, ==, 2);
921 g_assert_cmpint (data.num_connection_attempts, ==, 3);
922 g_assert (!g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
923 g_idle_add (on_do_disconnect_in_idle, c2);
924 g_debug ("==================================================");
925 g_debug ("==================================================");
926 g_debug ("==================================================");
927 g_debug ("waiting for disconnect on connection %p, stream %p",
928 data.current_connections->pdata[1],
929 g_dbus_connection_get_stream (data.current_connections->pdata[1]));
931 g_timeout_add (2000, check_connection, &data);
932 //_g_assert_signal_received (G_DBUS_CONNECTION (data.current_connections->pdata[1]), "closed");
933 g_main_loop_run (loop);
934 g_assert (g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
935 g_ptr_array_set_size (data.current_connections, 1); /* remove disconnected connection object */
938 /* unref the server and stop listening for new connections
940 * This won't bring down the established connections - check that c is still connected
941 * by invoking a method
943 //g_socket_service_stop (service);
944 //g_object_unref (service);
945 g_dbus_server_stop (server);
946 g_object_unref (server);
950 result = g_dbus_proxy_call_sync (proxy,
952 g_variant_new ("(s)", "Hey Again Peer!"),
953 G_DBUS_CALL_FLAGS_NONE,
955 NULL, /* GCancellable */
957 g_assert_no_error (error);
958 g_variant_get (result, "(&s)", &s);
959 g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
960 g_variant_unref (result);
961 g_assert_cmpint (data.num_method_calls, ==, 5);
964 /* TODO: THIS TEST DOESN'T WORK YET */
966 /* now disconnect from the server side - check that the client side gets the signal */
967 g_assert_cmpint (data.current_connections->len, ==, 1);
968 g_assert (G_DBUS_CONNECTION (data.current_connections->pdata[0]) != c);
969 g_dbus_connection_disconnect (G_DBUS_CONNECTION (data.current_connections->pdata[0]));
970 if (!g_dbus_connection_get_is_disconnected (c))
971 _g_assert_signal_received (c, "closed");
972 g_assert (g_dbus_connection_get_is_disconnected (c));
976 g_ptr_array_unref (data.current_connections);
977 g_object_unref (proxy);
979 g_main_loop_quit (service_loop);
980 g_thread_join (service_thread);
983 /* ---------------------------------------------------------------------------------------------------- */
988 GMainContext *context;
995 dmp_data_free (DmpData *data)
997 g_main_loop_unref (data->loop);
998 g_main_context_unref (data->context);
999 g_object_unref (data->server);
1000 g_list_free_full (data->connections, g_object_unref);
1005 dmp_on_method_call (GDBusConnection *connection,
1006 const gchar *sender,
1007 const gchar *object_path,
1008 const gchar *interface_name,
1009 const gchar *method_name,
1010 GVariant *parameters,
1011 GDBusMethodInvocation *invocation,
1014 //DmpData *data = user_data;
1017 g_variant_get (parameters,
1021 g_dbus_method_invocation_return_value (invocation,
1022 g_variant_new ("(i)", first + second));
1025 static const GDBusInterfaceVTable dmp_interface_vtable =
1028 NULL, /* get_property */
1029 NULL /* set_property */
1033 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
1035 dmp_on_new_connection (GDBusServer *server,
1036 GDBusConnection *connection,
1039 DmpData *data = user_data;
1040 GDBusNodeInfo *node;
1043 /* accept the connection */
1044 data->connections = g_list_prepend (data->connections, g_object_ref (connection));
1047 node = g_dbus_node_info_new_for_xml ("<node>"
1048 " <interface name='org.gtk.GDBus.DmpInterface'>"
1049 " <method name='AddPair'>"
1050 " <arg type='i' name='first' direction='in'/>"
1051 " <arg type='i' name='second' direction='in'/>"
1052 " <arg type='i' name='sum' direction='out'/>"
1057 g_assert_no_error (error);
1059 /* sleep 100ms before exporting an object - this is to test that
1060 * G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING really works
1061 * (GDBusServer uses this feature).
1063 usleep (100 * 1000);
1065 /* export an object */
1067 g_dbus_connection_register_object (connection,
1069 node->interfaces[0],
1070 &dmp_interface_vtable,
1074 g_dbus_node_info_unref (node);
1080 dmp_thread_func (gpointer user_data)
1082 DmpData *data = user_data;
1086 data->context = g_main_context_new ();
1087 g_main_context_push_thread_default (data->context);
1090 guid = g_dbus_generate_guid ();
1091 data->server = g_dbus_server_new_sync (tmp_address,
1092 G_DBUS_SERVER_FLAGS_NONE,
1094 NULL, /* GDBusAuthObserver */
1095 NULL, /* GCancellable */
1097 g_assert_no_error (error);
1098 g_signal_connect (data->server,
1100 G_CALLBACK (dmp_on_new_connection),
1103 g_dbus_server_start (data->server);
1105 data->loop = g_main_loop_new (data->context, FALSE);
1106 g_main_loop_run (data->loop);
1108 g_main_context_pop_thread_default (data->context);
1115 delayed_message_processing (void)
1119 GThread *service_thread;
1122 data = g_new0 (DmpData, 1);
1124 service_thread = g_thread_new ("dmp",
1127 while (data->server == NULL || !g_dbus_server_is_active (data->server))
1130 for (n = 0; n < 5; n++)
1137 c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data->server),
1138 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1139 NULL, /* GDBusAuthObserver */
1140 NULL, /* GCancellable */
1142 g_assert_no_error (error);
1145 res = g_dbus_connection_call_sync (c,
1146 NULL, /* bus name */
1148 "org.gtk.GDBus.DmpInterface",
1150 g_variant_new ("(ii)", 2, n),
1151 G_VARIANT_TYPE ("(i)"),
1152 G_DBUS_CALL_FLAGS_NONE,
1153 -1, /* timeout_msec */
1154 NULL, /* GCancellable */
1156 g_assert_no_error (error);
1157 g_variant_get (res, "(i)", &val);
1158 g_assert_cmpint (val, ==, 2 + n);
1159 g_variant_unref (res);
1163 g_main_loop_quit (data->loop);
1164 g_thread_join (service_thread);
1165 dmp_data_free (data);
1168 /* ---------------------------------------------------------------------------------------------------- */
1171 nonce_tcp_on_authorize_authenticated_peer (GDBusAuthObserver *observer,
1173 GCredentials *credentials,
1176 PeerData *data = user_data;
1177 gboolean authorized;
1179 data->num_connection_attempts++;
1182 if (!data->accept_connection)
1185 g_main_loop_quit (loop);
1191 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
1193 nonce_tcp_on_new_connection (GDBusServer *server,
1194 GDBusConnection *connection,
1197 PeerData *data = user_data;
1199 g_ptr_array_add (data->current_connections, g_object_ref (connection));
1201 g_main_loop_quit (loop);
1207 nonce_tcp_service_thread_func (gpointer user_data)
1209 PeerData *data = user_data;
1210 GMainContext *service_context;
1211 GDBusAuthObserver *observer;
1214 service_context = g_main_context_new ();
1215 g_main_context_push_thread_default (service_context);
1218 observer = g_dbus_auth_observer_new ();
1219 server = g_dbus_server_new_sync ("nonce-tcp:",
1220 G_DBUS_SERVER_FLAGS_NONE,
1223 NULL, /* cancellable */
1225 g_assert_no_error (error);
1227 g_signal_connect (server,
1229 G_CALLBACK (nonce_tcp_on_new_connection),
1231 g_signal_connect (observer,
1232 "authorize-authenticated-peer",
1233 G_CALLBACK (nonce_tcp_on_authorize_authenticated_peer),
1235 g_object_unref (observer);
1237 g_dbus_server_start (server);
1239 create_service_loop (service_context);
1240 g_main_loop_run (service_loop);
1242 g_main_context_pop_thread_default (service_context);
1244 teardown_service_loop ();
1245 g_main_context_unref (service_context);
1247 /* test code specifically unrefs the server - see below */
1248 g_assert (server == NULL);
1254 test_nonce_tcp (void)
1258 GThread *service_thread;
1263 const gchar *address;
1265 memset (&data, '\0', sizeof (PeerData));
1266 data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
1270 service_thread = g_thread_new ("nonce-tcp-service",
1271 nonce_tcp_service_thread_func,
1273 await_service_loop ();
1274 g_assert (server != NULL);
1276 /* bring up a connection and accept it */
1277 data.accept_connection = TRUE;
1279 c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
1280 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1281 NULL, /* GDBusAuthObserver */
1282 NULL, /* cancellable */
1284 g_assert_no_error (error);
1285 g_assert (c != NULL);
1286 while (data.current_connections->len < 1)
1288 g_assert_cmpint (data.current_connections->len, ==, 1);
1289 g_assert_cmpint (data.num_connection_attempts, ==, 1);
1290 g_assert (g_dbus_connection_get_unique_name (c) == NULL);
1291 g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
1294 /* now, try to subvert the nonce file (this assumes noncefile is the last key/value pair)
1297 address = g_dbus_server_get_client_address (server);
1299 s = strstr (address, "noncefile=");
1300 g_assert (s != NULL);
1301 s += sizeof "noncefile=" - 1;
1302 nonce_file = g_strdup (s);
1304 /* First try invalid data in the nonce file - this will actually
1305 * make the client send this and the server will reject it. The way
1306 * it works is that if the nonce doesn't match, the server will
1307 * simply close the connection. So, from the client point of view,
1308 * we can see a variety of errors.
1311 res = g_file_set_contents (nonce_file,
1315 g_assert_no_error (error);
1317 c = g_dbus_connection_new_for_address_sync (address,
1318 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1319 NULL, /* GDBusAuthObserver */
1320 NULL, /* cancellable */
1322 _g_assert_error_domain (error, G_IO_ERROR);
1323 g_error_free (error);
1324 g_assert (c == NULL);
1326 /* Then try with a nonce-file of incorrect length - this will make
1327 * the client complain - we won't even try connecting to the server
1331 res = g_file_set_contents (nonce_file,
1332 "0123456789012345_",
1335 g_assert_no_error (error);
1337 c = g_dbus_connection_new_for_address_sync (address,
1338 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1339 NULL, /* GDBusAuthObserver */
1340 NULL, /* cancellable */
1342 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1343 g_error_free (error);
1344 g_assert (c == NULL);
1346 /* Finally try with no nonce-file at all */
1347 g_assert_cmpint (g_unlink (nonce_file), ==, 0);
1349 c = g_dbus_connection_new_for_address_sync (address,
1350 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1351 NULL, /* GDBusAuthObserver */
1352 NULL, /* cancellable */
1354 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1355 g_error_free (error);
1356 g_assert (c == NULL);
1358 g_free (nonce_file);
1360 g_dbus_server_stop (server);
1361 g_object_unref (server);
1364 g_main_loop_quit (service_loop);
1365 g_thread_join (service_thread);
1369 test_credentials (void)
1371 GCredentials *c1, *c2;
1375 c1 = g_credentials_new ();
1376 c2 = g_credentials_new ();
1379 if (g_credentials_set_unix_user (c2, getuid (), &error))
1380 g_assert_no_error (error);
1382 g_clear_error (&error);
1383 g_assert (g_credentials_is_same_user (c1, c2, &error));
1384 g_assert_no_error (error);
1386 desc = g_credentials_to_string (c1);
1387 g_assert (desc != NULL);
1390 g_object_unref (c1);
1391 g_object_unref (c2);
1394 /* ---------------------------------------------------------------------------------------------------- */
1397 tcp_anonymous_on_new_connection (GDBusServer *server,
1398 GDBusConnection *connection,
1401 gboolean *seen_connection = user_data;
1402 *seen_connection = TRUE;
1407 tcp_anonymous_service_thread_func (gpointer user_data)
1409 gboolean *seen_connection = user_data;
1410 GMainContext *service_context;
1413 service_context = g_main_context_new ();
1414 g_main_context_push_thread_default (service_context);
1417 server = g_dbus_server_new_sync ("tcp:",
1418 G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS,
1420 NULL, /* GDBusObserver* */
1421 NULL, /* GCancellable* */
1423 g_assert_no_error (error);
1425 g_signal_connect (server,
1427 G_CALLBACK (tcp_anonymous_on_new_connection),
1430 g_dbus_server_start (server);
1432 create_service_loop (service_context);
1433 g_main_loop_run (service_loop);
1435 g_main_context_pop_thread_default (service_context);
1437 teardown_service_loop ();
1438 g_main_context_unref (service_context);
1444 test_tcp_anonymous (void)
1446 gboolean seen_connection;
1447 GThread *service_thread;
1448 GDBusConnection *connection;
1451 seen_connection = FALSE;
1452 service_thread = g_thread_new ("tcp-anon-service",
1453 tcp_anonymous_service_thread_func,
1455 await_service_loop ();
1456 g_assert (server != NULL);
1459 connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
1460 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1461 NULL, /* GDBusAuthObserver* */
1462 NULL, /* GCancellable */
1464 g_assert_no_error (error);
1465 g_assert (connection != NULL);
1467 while (!seen_connection)
1470 g_object_unref (connection);
1472 g_main_loop_quit (service_loop);
1473 g_dbus_server_stop (server);
1474 g_object_unref (server);
1477 g_thread_join (service_thread);
1480 /* ---------------------------------------------------------------------------------------------------- */
1482 static GDBusServer *codegen_server = NULL;
1485 codegen_on_animal_poke (ExampleAnimal *animal,
1486 GDBusMethodInvocation *invocation,
1488 gboolean make_happy,
1491 if ((make_sad && make_happy) || (!make_sad && !make_happy))
1493 g_main_loop_quit (service_loop);
1495 g_dbus_method_invocation_return_dbus_error (invocation,
1496 "org.gtk.GDBus.Examples.ObjectManager.Error.Failed",
1497 "Exactly one of make_sad or make_happy must be TRUE");
1503 if (g_strcmp0 (example_animal_get_mood (animal), "Sad") == 0)
1505 g_dbus_method_invocation_return_dbus_error (invocation,
1506 "org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad",
1507 "Sad animal is already sad");
1511 example_animal_set_mood (animal, "Sad");
1512 example_animal_complete_poke (animal, invocation);
1518 if (g_strcmp0 (example_animal_get_mood (animal), "Happy") == 0)
1520 g_dbus_method_invocation_return_dbus_error (invocation,
1521 "org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy",
1522 "Happy animal is already happy");
1526 example_animal_set_mood (animal, "Happy");
1527 example_animal_complete_poke (animal, invocation);
1531 g_assert_not_reached ();
1534 return TRUE; /* to indicate that the method was handled */
1537 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
1539 codegen_on_new_connection (GDBusServer *server,
1540 GDBusConnection *connection,
1543 ExampleAnimal *animal = user_data;
1544 GError *error = NULL;
1546 /* g_print ("Client connected.\n" */
1547 /* "Negotiated capabilities: unix-fd-passing=%d\n", */
1548 /* g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); */
1550 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (animal), connection,
1551 "/Example/Animals/000", &error);
1552 g_assert_no_error (error);
1558 codegen_service_thread_func (gpointer user_data)
1560 GMainContext *service_context;
1561 ExampleAnimal *animal;
1562 GError *error = NULL;
1564 service_context = g_main_context_new ();
1565 g_main_context_push_thread_default (service_context);
1567 /* Create the animal in the right thread context */
1568 animal = example_animal_skeleton_new ();
1570 /* Handle Poke() D-Bus method invocations on the .Animal interface */
1571 g_signal_connect (animal, "handle-poke",
1572 G_CALLBACK (codegen_on_animal_poke),
1573 NULL); /* user_data */
1575 codegen_server = g_dbus_server_new_sync (tmp_address,
1576 G_DBUS_SERVER_FLAGS_NONE,
1578 NULL, /* observer */
1579 NULL, /* cancellable */
1581 g_assert_no_error (error);
1582 g_dbus_server_start (codegen_server);
1584 g_signal_connect (codegen_server, "new-connection",
1585 G_CALLBACK (codegen_on_new_connection),
1588 create_service_loop (service_context);
1589 g_main_loop_run (service_loop);
1591 g_object_unref (animal);
1593 g_main_context_pop_thread_default (service_context);
1595 teardown_service_loop ();
1596 g_main_context_unref (service_context);
1598 g_dbus_server_stop (codegen_server);
1599 g_object_unref (codegen_server);
1600 codegen_server = NULL;
1607 codegen_quit_mainloop_timeout (gpointer data)
1609 g_main_loop_quit (loop);
1614 codegen_test_peer (void)
1616 GDBusConnection *connection;
1617 ExampleAnimal *animal1, *animal2;
1618 GThread *service_thread;
1619 GError *error = NULL;
1622 /* bring up a server - we run the server in a different thread to avoid deadlocks */
1623 service_thread = g_thread_new ("codegen_test_peer",
1624 codegen_service_thread_func,
1626 await_service_loop ();
1627 g_assert (codegen_server != NULL);
1629 /* Get an animal 1 ... */
1630 connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
1631 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1632 NULL, /* GDBusAuthObserver */
1633 NULL, /* cancellable */
1635 g_assert_no_error (error);
1636 g_assert (connection != NULL);
1638 animal1 = example_animal_proxy_new_sync (connection, 0, NULL,
1639 "/Example/Animals/000", NULL, &error);
1640 g_assert_no_error (error);
1641 g_assert (animal1 != NULL);
1642 g_object_unref (connection);
1644 /* Get animal 2 ... */
1645 connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
1646 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1647 NULL, /* GDBusAuthObserver */
1648 NULL, /* cancellable */
1650 g_assert_no_error (error);
1651 g_assert (connection != NULL);
1653 animal2 = example_animal_proxy_new_sync (connection, 0, NULL,
1654 "/Example/Animals/000", NULL, &error);
1655 g_assert_no_error (error);
1656 g_assert (animal2 != NULL);
1657 g_object_unref (connection);
1659 /* Make animal sad via animal1 */
1660 example_animal_call_poke_sync (animal1, TRUE, FALSE, NULL, &error);
1661 g_assert_no_error (error);
1663 /* Poke server and make sure animal is updated */
1664 value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal1),
1665 "org.freedesktop.DBus.Peer.Ping",
1666 NULL, G_DBUS_CALL_FLAGS_NONE, -1,
1668 g_assert_no_error (error);
1669 g_assert (value != NULL);
1670 g_variant_unref (value);
1672 /* Give the proxies a chance to refresh in the defaul main loop */
1673 g_timeout_add (100, codegen_quit_mainloop_timeout, NULL);
1674 g_main_loop_run (loop);
1676 /* Assert animals are sad */
1677 g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Sad");
1678 g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Sad");
1680 /* Make animal happy via animal2 */
1681 example_animal_call_poke_sync (animal2, FALSE, TRUE, NULL, &error);
1682 g_assert_no_error (error);
1684 /* Poke server and make sure animal is updated */
1685 value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal2),
1686 "org.freedesktop.DBus.Peer.Ping",
1687 NULL, G_DBUS_CALL_FLAGS_NONE, -1,
1689 g_assert_no_error (error);
1690 g_assert (value != NULL);
1691 g_variant_unref (value);
1693 /* Give the proxies a chance to refresh in the defaul main loop */
1694 g_timeout_add (1000, codegen_quit_mainloop_timeout, NULL);
1695 g_main_loop_run (loop);
1697 /* Assert animals are happy */
1698 g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Happy");
1699 g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Happy");
1701 /* This final call making the animal happy and sad will cause
1702 * the server to quit, when the server quits we dont get property
1703 * change notifications anyway because those are done from an idle handler
1705 example_animal_call_poke_sync (animal2, TRUE, TRUE, NULL, &error);
1707 g_object_unref (animal1);
1708 g_object_unref (animal2);
1709 g_thread_join (service_thread);
1712 /* ---------------------------------------------------------------------------------------------------- */
1720 GDBusNodeInfo *introspection_data = NULL;
1721 gchar *tmpdir = NULL;
1723 g_test_init (&argc, &argv, NULL);
1725 introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
1726 g_assert (introspection_data != NULL);
1727 test_interface_introspection_data = introspection_data->interfaces[0];
1729 test_guid = g_dbus_generate_guid ();
1733 if (g_unix_socket_address_abstract_names_supported ())
1734 tmp_address = g_strdup ("unix:tmpdir=/tmp/gdbus-test-");
1737 tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
1738 tmp_address = g_strdup_printf ("unix:tmpdir=%s", tmpdir);
1742 tmp_address = g_strdup ("nonce-tcp:");
1744 /* all the tests rely on a shared main loop */
1745 loop = g_main_loop_new (NULL, FALSE);
1747 g_test_add_func ("/gdbus/peer-to-peer", test_peer);
1748 g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing);
1749 g_test_add_func ("/gdbus/nonce-tcp", test_nonce_tcp);
1751 g_test_add_func ("/gdbus/tcp-anonymous", test_tcp_anonymous);
1752 g_test_add_func ("/gdbus/credentials", test_credentials);
1753 g_test_add_func ("/gdbus/codegen-peer-to-peer", codegen_test_peer);
1757 g_main_loop_unref (loop);
1759 g_dbus_node_info_unref (introspection_data);
1761 g_free (tmp_address);