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>
28 #include <sys/types.h>
33 #include <glib/gstdio.h>
35 #include <gio/gunixsocketaddress.h>
36 #include <gio/gunixfdlist.h>
38 /* for struct ucred */
41 #include <sys/types.h>
42 #include <sys/socket.h>
45 /* used in test_overflow */
47 #include <gio/gunixconnection.h>
50 #include "gdbus-tests.h"
53 static gboolean is_unix = TRUE;
55 static gboolean is_unix = FALSE;
58 static gchar *test_guid = NULL;
59 static GMainLoop *service_loop = NULL;
60 static GDBusServer *server = NULL;
61 static GMainLoop *loop = NULL;
63 /* ---------------------------------------------------------------------------------------------------- */
64 /* Test that peer-to-peer connections work */
65 /* ---------------------------------------------------------------------------------------------------- */
70 gboolean accept_connection;
71 gint num_connection_attempts;
72 GPtrArray *current_connections;
73 guint num_method_calls;
74 gboolean signal_received;
77 static const gchar *test_interface_introspection_xml =
79 " <interface name='org.gtk.GDBus.PeerTestInterface'>"
80 " <method name='HelloPeer'>"
81 " <arg type='s' name='greeting' direction='in'/>"
82 " <arg type='s' name='response' direction='out'/>"
84 " <method name='EmitSignal'/>"
85 " <method name='EmitSignalWithNameSet'/>"
86 " <method name='OpenFile'>"
87 " <arg type='s' name='path' direction='in'/>"
89 " <signal name='PeerSignal'>"
90 " <arg type='s' name='a_string'/>"
92 " <property type='s' name='PeerProperty' access='read'/>"
95 static GDBusInterfaceInfo *test_interface_introspection_data = NULL;
98 test_interface_method_call (GDBusConnection *connection,
100 const gchar *object_path,
101 const gchar *interface_name,
102 const gchar *method_name,
103 GVariant *parameters,
104 GDBusMethodInvocation *invocation,
107 PeerData *data = user_data;
109 data->num_method_calls++;
111 g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
112 g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
114 if (g_strcmp0 (method_name, "HelloPeer") == 0)
116 const gchar *greeting;
119 g_variant_get (parameters, "(&s)", &greeting);
121 response = g_strdup_printf ("You greeted me with '%s'.",
123 g_dbus_method_invocation_return_value (invocation,
124 g_variant_new ("(s)", response));
127 else if (g_strcmp0 (method_name, "EmitSignal") == 0)
132 g_dbus_connection_emit_signal (connection,
134 "/org/gtk/GDBus/PeerTestObject",
135 "org.gtk.GDBus.PeerTestInterface",
139 g_assert_no_error (error);
140 g_dbus_method_invocation_return_value (invocation, NULL);
142 else if (g_strcmp0 (method_name, "EmitSignalWithNameSet") == 0)
146 GDBusMessage *message;
148 message = g_dbus_message_new_signal ("/org/gtk/GDBus/PeerTestObject",
149 "org.gtk.GDBus.PeerTestInterface",
150 "PeerSignalWithNameSet");
151 g_dbus_message_set_sender (message, ":1.42");
154 ret = g_dbus_connection_send_message (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error);
155 g_assert_no_error (error);
157 g_object_unref (message);
159 g_dbus_method_invocation_return_value (invocation, NULL);
161 else if (g_strcmp0 (method_name, "OpenFile") == 0)
168 GUnixFDList *fd_list;
170 g_variant_get (parameters, "(&s)", &path);
172 fd_list = g_unix_fd_list_new ();
176 fd = open (path, O_RDONLY);
177 g_unix_fd_list_append (fd_list, fd, &error);
178 g_assert_no_error (error);
181 reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
182 g_dbus_message_set_unix_fd_list (reply, fd_list);
183 g_object_unref (invocation);
186 g_dbus_connection_send_message (connection,
188 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
189 NULL, /* out_serial */
191 g_assert_no_error (error);
192 g_object_unref (reply);
194 g_dbus_method_invocation_return_dbus_error (invocation,
195 "org.gtk.GDBus.NotOnUnix",
196 "Your OS does not support file descriptor passing");
201 g_assert_not_reached ();
206 test_interface_get_property (GDBusConnection *connection,
208 const gchar *object_path,
209 const gchar *interface_name,
210 const gchar *property_name,
214 g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
215 g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
216 g_assert_cmpstr (property_name, ==, "PeerProperty");
218 return g_variant_new_string ("ThePropertyValue");
222 static const GDBusInterfaceVTable test_interface_vtable =
224 test_interface_method_call,
225 test_interface_get_property,
226 NULL /* set_property */
230 on_proxy_signal_received (GDBusProxy *proxy,
233 GVariant *parameters,
236 PeerData *data = user_data;
238 data->signal_received = TRUE;
240 g_assert (sender_name == NULL);
241 g_assert_cmpstr (signal_name, ==, "PeerSignal");
242 g_main_loop_quit (loop);
246 on_proxy_signal_received_with_name_set (GDBusProxy *proxy,
249 GVariant *parameters,
252 PeerData *data = user_data;
254 data->signal_received = TRUE;
256 g_assert_cmpstr (sender_name, ==, ":1.42");
257 g_assert_cmpstr (signal_name, ==, "PeerSignalWithNameSet");
258 g_main_loop_quit (loop);
261 /* ---------------------------------------------------------------------------------------------------- */
264 on_authorize_authenticated_peer (GDBusAuthObserver *observer,
266 GCredentials *credentials,
269 PeerData *data = user_data;
272 data->num_connection_attempts++;
275 if (!data->accept_connection)
278 g_main_loop_quit (loop);
284 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
286 on_new_connection (GDBusServer *server,
287 GDBusConnection *connection,
290 PeerData *data = user_data;
294 //g_print ("Client connected.\n"
295 // "Negotiated capabilities: unix-fd-passing=%d\n",
296 // g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
298 g_ptr_array_add (data->current_connections, g_object_ref (connection));
300 /* export object on the newly established connection */
302 reg_id = g_dbus_connection_register_object (connection,
303 "/org/gtk/GDBus/PeerTestObject",
304 test_interface_introspection_data,
305 &test_interface_vtable,
307 NULL, /* GDestroyNotify for data */
309 g_assert_no_error (error);
310 g_assert (reg_id > 0);
312 g_main_loop_quit (loop);
316 service_thread_func (gpointer user_data)
318 PeerData *data = user_data;
319 GMainContext *service_context;
320 GDBusAuthObserver *observer;
323 service_context = g_main_context_new ();
324 g_main_context_push_thread_default (service_context);
327 observer = g_dbus_auth_observer_new ();
328 server = g_dbus_server_new_sync (is_unix ? "unix:tmpdir=/tmp/gdbus-test-" : "nonce-tcp:",
329 G_DBUS_SERVER_FLAGS_NONE,
332 NULL, /* cancellable */
334 g_assert_no_error (error);
336 g_signal_connect (server,
338 G_CALLBACK (on_new_connection),
340 g_signal_connect (observer,
341 "authorize-authenticated-peer",
342 G_CALLBACK (on_authorize_authenticated_peer),
344 g_object_unref (observer);
346 g_dbus_server_start (server);
348 service_loop = g_main_loop_new (service_context, FALSE);
349 g_main_loop_run (service_loop);
351 g_main_context_pop_thread_default (service_context);
353 g_main_loop_unref (service_loop);
354 g_main_context_unref (service_context);
356 /* test code specifically unrefs the server - see below */
357 g_assert (server == NULL);
364 on_incoming_connection (GSocketService *service,
365 GSocketConnection *socket_connection,
366 GObject *source_object,
369 PeerData *data = user_data;
371 if (data->accept_connection)
375 GDBusConnection *connection;
378 connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
380 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
381 NULL, /* cancellable */
383 g_assert_no_error (error);
385 g_ptr_array_add (data->current_connections, connection);
387 /* export object on the newly established connection */
389 reg_id = g_dbus_connection_register_object (connection,
390 "/org/gtk/GDBus/PeerTestObject",
391 &test_interface_introspection_data,
392 &test_interface_vtable,
394 NULL, /* GDestroyNotify for data */
396 g_assert_no_error (error);
397 g_assert (reg_id > 0);
402 /* don't do anything */
405 data->num_connection_attempts++;
407 g_main_loop_quit (loop);
409 /* stops other signal handlers from being invoked */
414 service_thread_func (gpointer data)
416 GMainContext *service_context;
418 GSocketAddress *address;
421 service_context = g_main_context_new ();
422 g_main_context_push_thread_default (service_context);
424 socket_path = g_strdup_printf ("/tmp/gdbus-test-pid-%d", getpid ());
425 address = g_unix_socket_address_new (socket_path);
427 service = g_socket_service_new ();
429 g_socket_listener_add_address (G_SOCKET_LISTENER (service),
431 G_SOCKET_TYPE_STREAM,
432 G_SOCKET_PROTOCOL_DEFAULT,
433 NULL, /* source_object */
434 NULL, /* effective_address */
436 g_assert_no_error (error);
437 g_signal_connect (service,
439 G_CALLBACK (on_incoming_connection),
441 g_socket_service_start (service);
443 service_loop = g_main_loop_new (service_context, FALSE);
444 g_main_loop_run (service_loop);
446 g_main_context_pop_thread_default (service_context);
448 g_main_loop_unref (service_loop);
449 g_main_context_unref (service_context);
451 g_object_unref (address);
452 g_free (socket_path);
457 /* ---------------------------------------------------------------------------------------------------- */
461 check_connection (gpointer user_data)
463 PeerData *data = user_data;
466 for (n = 0; n < data->current_connections->len; n++)
471 c = G_DBUS_CONNECTION (data->current_connections->pdata[n]);
472 stream = g_dbus_connection_get_stream (c);
474 g_debug ("In check_connection for %d: connection %p, stream %p", n, c, stream);
475 g_debug ("closed = %d", g_io_stream_is_closed (stream));
478 socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
479 g_debug ("socket_closed = %d", g_socket_is_closed (socket));
480 g_debug ("socket_condition_check = %d", g_socket_condition_check (socket, G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP));
486 num_read = g_input_stream_read (g_io_stream_get_input_stream (stream),
493 g_debug ("error: %s", error->message);
494 g_error_free (error);
498 g_debug ("no error, read %d bytes", (gint) num_read);
506 on_do_disconnect_in_idle (gpointer data)
508 GDBusConnection *c = G_DBUS_CONNECTION (data);
509 g_debug ("GDC %p has ref_count %d", c, G_OBJECT (c)->ref_count);
510 g_dbus_connection_disconnect (c);
527 GThread *service_thread;
528 gulong signal_handler_id;
530 memset (&data, '\0', sizeof (PeerData));
531 data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
533 /* first try to connect when there is no server */
535 c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" :
536 /* NOTE: Even if something is listening on port 12345 the connection
537 * will fail because the nonce file doesn't exist */
538 "nonce-tcp:host=localhost,port=12345,noncefile=this-does-not-exist-gdbus",
539 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
540 NULL, /* GDBusAuthObserver */
541 NULL, /* cancellable */
543 _g_assert_error_domain (error, G_IO_ERROR);
544 g_assert (!g_dbus_error_is_remote_error (error));
545 g_clear_error (&error);
546 g_assert (c == NULL);
548 /* bring up a server - we run the server in a different thread to avoid deadlocks */
550 service_thread = g_thread_create (service_thread_func,
554 while (service_loop == NULL)
556 g_assert (server != NULL);
558 /* bring up a connection and accept it */
559 data.accept_connection = TRUE;
561 c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
562 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
563 NULL, /* GDBusAuthObserver */
564 NULL, /* cancellable */
566 g_assert_no_error (error);
567 g_assert (c != NULL);
568 while (data.current_connections->len < 1)
569 g_main_loop_run (loop);
570 g_assert_cmpint (data.current_connections->len, ==, 1);
571 g_assert_cmpint (data.num_connection_attempts, ==, 1);
572 g_assert (g_dbus_connection_get_unique_name (c) == NULL);
573 g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
575 /* check that we create a proxy, read properties, receive signals and invoke
576 * the HelloPeer() method. Since the server runs in another thread it's fine
577 * to use synchronous blocking API here.
580 proxy = g_dbus_proxy_new_sync (c,
581 G_DBUS_PROXY_FLAGS_NONE,
584 "/org/gtk/GDBus/PeerTestObject",
585 "org.gtk.GDBus.PeerTestInterface",
586 NULL, /* GCancellable */
588 g_assert_no_error (error);
589 g_assert (proxy != NULL);
591 value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
592 g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
594 /* try invoking a method */
596 result = g_dbus_proxy_call_sync (proxy,
598 g_variant_new ("(s)", "Hey Peer!"),
599 G_DBUS_CALL_FLAGS_NONE,
601 NULL, /* GCancellable */
603 g_assert_no_error (error);
604 g_variant_get (result, "(&s)", &s);
605 g_assert_cmpstr (s, ==, "You greeted me with 'Hey Peer!'.");
606 g_variant_unref (result);
607 g_assert_cmpint (data.num_method_calls, ==, 1);
609 /* make the other peer emit a signal - catch it */
610 signal_handler_id = g_signal_connect (proxy,
612 G_CALLBACK (on_proxy_signal_received),
614 g_assert (!data.signal_received);
615 g_dbus_proxy_call (proxy,
617 NULL, /* no arguments */
618 G_DBUS_CALL_FLAGS_NONE,
620 NULL, /* GCancellable */
621 NULL, /* GAsyncReadyCallback - we don't care about the result */
622 NULL); /* user_data */
623 g_main_loop_run (loop);
624 g_assert (data.signal_received);
625 g_assert_cmpint (data.num_method_calls, ==, 2);
626 g_signal_handler_disconnect (proxy, signal_handler_id);
628 /* Also ensure that messages with the sender header-field set gets
629 * delivered to the proxy - note that this doesn't really make sense
630 * e.g. names are meaning-less in a peer-to-peer case... but we
631 * support it because it makes sense in certain bridging
632 * applications - see e.g. #623815.
634 signal_handler_id = g_signal_connect (proxy,
636 G_CALLBACK (on_proxy_signal_received_with_name_set),
638 data.signal_received = FALSE;
639 g_dbus_proxy_call (proxy,
640 "EmitSignalWithNameSet",
641 NULL, /* no arguments */
642 G_DBUS_CALL_FLAGS_NONE,
644 NULL, /* GCancellable */
645 NULL, /* GAsyncReadyCallback - we don't care about the result */
646 NULL); /* user_data */
647 g_main_loop_run (loop);
648 g_assert (data.signal_received);
649 g_assert_cmpint (data.num_method_calls, ==, 3);
650 g_signal_handler_disconnect (proxy, signal_handler_id);
652 /* check for UNIX fd passing */
655 GDBusMessage *method_call_message;
656 GDBusMessage *method_reply_message;
657 GUnixFDList *fd_list;
664 method_call_message = g_dbus_message_new_method_call (NULL, /* name */
665 "/org/gtk/GDBus/PeerTestObject",
666 "org.gtk.GDBus.PeerTestInterface",
668 g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", "/etc/hosts"));
670 method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
672 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
674 NULL, /* out_serial */
675 NULL, /* cancellable */
677 g_assert_no_error (error);
678 g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
679 fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
680 g_assert (fd_list != NULL);
681 g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
683 fd = g_unix_fd_list_get (fd_list, 0, &error);
684 g_assert_no_error (error);
685 g_object_unref (method_call_message);
686 g_object_unref (method_reply_message);
688 memset (buf, '\0', sizeof (buf));
689 len = read (fd, buf, sizeof (buf) - 1);
693 g_file_get_contents ("/etc/hosts",
697 g_assert_no_error (error);
698 if (len2 > sizeof (buf))
699 buf2[sizeof (buf)] = '\0';
700 g_assert_cmpstr (buf, ==, buf2);
705 result = g_dbus_proxy_call_sync (proxy,
707 g_variant_new ("(s)", "boo"),
708 G_DBUS_CALL_FLAGS_NONE,
710 NULL, /* GCancellable */
712 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
713 g_assert (result == NULL);
714 g_error_free (error);
715 #endif /* G_OS_UNIX */
717 /* Check that g_socket_get_credentials() work - this really should
718 * be in a GSocket-specific test suite but no such test suite exists
723 GCredentials *credentials;
724 socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (g_dbus_connection_get_stream (c)));
725 g_assert (G_IS_SOCKET (socket));
727 credentials = g_socket_get_credentials (socket, &error);
730 struct ucred *native_creds;
731 g_assert_no_error (error);
732 g_assert (G_IS_CREDENTIALS (credentials));
733 native_creds = g_credentials_get_native (credentials, G_CREDENTIALS_TYPE_LINUX_UCRED);
734 g_assert (native_creds != NULL);
735 g_assert (native_creds->uid == getuid ());
736 g_assert (native_creds->gid == getgid ());
737 g_assert (native_creds->pid == getpid ());
739 g_object_unref (credentials);
741 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
742 g_assert (credentials == NULL);
747 /* bring up a connection - don't accept it - this should fail
749 data.accept_connection = FALSE;
751 c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
752 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
753 NULL, /* GDBusAuthObserver */
754 NULL, /* cancellable */
756 _g_assert_error_domain (error, G_IO_ERROR);
757 g_assert (c2 == NULL);
760 /* TODO: THIS TEST DOESN'T WORK YET */
762 /* bring up a connection - accept it.. then disconnect from the client side - check
763 * that the server side gets the disconnect signal.
766 data.accept_connection = TRUE;
767 c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
768 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
769 NULL, /* GDBusAuthObserver */
770 NULL, /* cancellable */
772 g_assert_no_error (error);
773 g_assert (c2 != NULL);
774 g_assert (!g_dbus_connection_get_is_disconnected (c2));
775 while (data.num_connection_attempts < 3)
776 g_main_loop_run (loop);
777 g_assert_cmpint (data.current_connections->len, ==, 2);
778 g_assert_cmpint (data.num_connection_attempts, ==, 3);
779 g_assert (!g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
780 g_idle_add (on_do_disconnect_in_idle, c2);
781 g_debug ("==================================================");
782 g_debug ("==================================================");
783 g_debug ("==================================================");
784 g_debug ("waiting for disconnect on connection %p, stream %p",
785 data.current_connections->pdata[1],
786 g_dbus_connection_get_stream (data.current_connections->pdata[1]));
788 g_timeout_add (2000, check_connection, &data);
789 //_g_assert_signal_received (G_DBUS_CONNECTION (data.current_connections->pdata[1]), "closed");
790 g_main_loop_run (loop);
791 g_assert (g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
792 g_ptr_array_set_size (data.current_connections, 1); /* remove disconnected connection object */
795 /* unref the server and stop listening for new connections
797 * This won't bring down the established connections - check that c is still connected
798 * by invoking a method
800 //g_socket_service_stop (service);
801 //g_object_unref (service);
802 g_dbus_server_stop (server);
803 g_object_unref (server);
807 result = g_dbus_proxy_call_sync (proxy,
809 g_variant_new ("(s)", "Hey Again Peer!"),
810 G_DBUS_CALL_FLAGS_NONE,
812 NULL, /* GCancellable */
814 g_assert_no_error (error);
815 g_variant_get (result, "(&s)", &s);
816 g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
817 g_variant_unref (result);
818 g_assert_cmpint (data.num_method_calls, ==, 5);
821 /* TODO: THIS TEST DOESN'T WORK YET */
823 /* now disconnect from the server side - check that the client side gets the signal */
824 g_assert_cmpint (data.current_connections->len, ==, 1);
825 g_assert (G_DBUS_CONNECTION (data.current_connections->pdata[0]) != c);
826 g_dbus_connection_disconnect (G_DBUS_CONNECTION (data.current_connections->pdata[0]));
827 if (!g_dbus_connection_get_is_disconnected (c))
828 _g_assert_signal_received (c, "closed");
829 g_assert (g_dbus_connection_get_is_disconnected (c));
833 g_ptr_array_unref (data.current_connections);
834 g_object_unref (proxy);
836 g_main_loop_quit (service_loop);
837 g_thread_join (service_thread);
840 /* ---------------------------------------------------------------------------------------------------- */
845 GMainContext *context;
852 dmp_data_free (DmpData *data)
854 g_main_loop_unref (data->loop);
855 g_main_context_unref (data->context);
856 g_object_unref (data->server);
857 g_list_foreach (data->connections, (GFunc) g_object_unref, NULL);
858 g_list_free (data->connections);
863 dmp_on_method_call (GDBusConnection *connection,
865 const gchar *object_path,
866 const gchar *interface_name,
867 const gchar *method_name,
868 GVariant *parameters,
869 GDBusMethodInvocation *invocation,
872 //DmpData *data = user_data;
875 g_variant_get (parameters,
879 g_dbus_method_invocation_return_value (invocation,
880 g_variant_new ("(i)", first + second));
883 static const GDBusInterfaceVTable dmp_interface_vtable =
886 NULL, /* get_property */
887 NULL /* set_property */
891 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
893 dmp_on_new_connection (GDBusServer *server,
894 GDBusConnection *connection,
897 DmpData *data = user_data;
901 /* accept the connection */
902 data->connections = g_list_prepend (data->connections, g_object_ref (connection));
905 node = g_dbus_node_info_new_for_xml ("<node>"
906 " <interface name='org.gtk.GDBus.DmpInterface'>"
907 " <method name='AddPair'>"
908 " <arg type='i' name='first' direction='in'/>"
909 " <arg type='i' name='second' direction='in'/>"
910 " <arg type='i' name='sum' direction='out'/>"
915 g_assert_no_error (error);
917 /* sleep 100ms before exporting an object - this is to test that
918 * G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING really works
919 * (GDBusServer uses this feature).
923 /* export an object */
925 g_dbus_connection_register_object (connection,
928 &dmp_interface_vtable,
932 g_dbus_node_info_unref (node);
936 dmp_thread_func (gpointer user_data)
938 DmpData *data = user_data;
942 data->context = g_main_context_new ();
943 g_main_context_push_thread_default (data->context);
946 guid = g_dbus_generate_guid ();
947 data->server = g_dbus_server_new_sync ("unix:tmpdir=/tmp/gdbus-test-",
948 G_DBUS_SERVER_FLAGS_NONE,
950 NULL, /* GDBusAuthObserver */
951 NULL, /* GCancellable */
953 g_assert_no_error (error);
954 g_signal_connect (data->server,
956 G_CALLBACK (dmp_on_new_connection),
959 g_dbus_server_start (data->server);
961 data->loop = g_main_loop_new (data->context, FALSE);
962 g_main_loop_run (data->loop);
964 g_main_context_pop_thread_default (data->context);
971 delayed_message_processing (void)
975 GThread *service_thread;
978 data = g_new0 (DmpData, 1);
981 service_thread = g_thread_create (dmp_thread_func,
985 while (data->server == NULL || !g_dbus_server_is_active (data->server))
988 for (n = 0; n < 5; n++)
995 c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data->server),
996 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
997 NULL, /* GDBusAuthObserver */
998 NULL, /* GCancellable */
1000 g_assert_no_error (error);
1003 res = g_dbus_connection_call_sync (c,
1004 NULL, /* bus name */
1006 "org.gtk.GDBus.DmpInterface",
1008 g_variant_new ("(ii)", 2, n),
1009 G_VARIANT_TYPE ("(i)"),
1010 G_DBUS_CALL_FLAGS_NONE,
1011 -1, /* timeout_msec */
1012 NULL, /* GCancellable */
1014 g_assert_no_error (error);
1015 g_variant_get (res, "(i)", &val);
1016 g_assert_cmpint (val, ==, 2 + n);
1017 g_variant_unref (res);
1021 g_main_loop_quit (data->loop);
1022 g_thread_join (service_thread);
1023 dmp_data_free (data);
1026 /* ---------------------------------------------------------------------------------------------------- */
1029 nonce_tcp_on_authorize_authenticated_peer (GDBusAuthObserver *observer,
1031 GCredentials *credentials,
1034 PeerData *data = user_data;
1035 gboolean authorized;
1037 data->num_connection_attempts++;
1040 if (!data->accept_connection)
1043 g_main_loop_quit (loop);
1049 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
1051 nonce_tcp_on_new_connection (GDBusServer *server,
1052 GDBusConnection *connection,
1055 PeerData *data = user_data;
1057 g_ptr_array_add (data->current_connections, g_object_ref (connection));
1059 g_main_loop_quit (loop);
1063 nonce_tcp_service_thread_func (gpointer user_data)
1065 PeerData *data = user_data;
1066 GMainContext *service_context;
1067 GDBusAuthObserver *observer;
1070 service_context = g_main_context_new ();
1071 g_main_context_push_thread_default (service_context);
1074 observer = g_dbus_auth_observer_new ();
1075 server = g_dbus_server_new_sync ("nonce-tcp:",
1076 G_DBUS_SERVER_FLAGS_NONE,
1079 NULL, /* cancellable */
1081 g_assert_no_error (error);
1083 g_signal_connect (server,
1085 G_CALLBACK (nonce_tcp_on_new_connection),
1087 g_signal_connect (observer,
1088 "authorize-authenticated-peer",
1089 G_CALLBACK (nonce_tcp_on_authorize_authenticated_peer),
1091 g_object_unref (observer);
1093 g_dbus_server_start (server);
1095 service_loop = g_main_loop_new (service_context, FALSE);
1096 g_main_loop_run (service_loop);
1098 g_main_context_pop_thread_default (service_context);
1100 g_main_loop_unref (service_loop);
1101 g_main_context_unref (service_context);
1103 /* test code specifically unrefs the server - see below */
1104 g_assert (server == NULL);
1110 test_nonce_tcp (void)
1114 GThread *service_thread;
1119 const gchar *address;
1121 memset (&data, '\0', sizeof (PeerData));
1122 data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
1126 service_loop = NULL;
1127 service_thread = g_thread_create (nonce_tcp_service_thread_func,
1131 while (service_loop == NULL)
1133 g_assert (server != NULL);
1136 /* bring up a connection and accept it */
1137 data.accept_connection = TRUE;
1139 c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
1140 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1141 NULL, /* GDBusAuthObserver */
1142 NULL, /* cancellable */
1144 g_assert_no_error (error);
1145 g_assert (c != NULL);
1146 while (data.current_connections->len < 1)
1147 g_main_loop_run (loop);
1148 g_assert_cmpint (data.current_connections->len, ==, 1);
1149 g_assert_cmpint (data.num_connection_attempts, ==, 1);
1150 g_assert (g_dbus_connection_get_unique_name (c) == NULL);
1151 g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
1154 /* now, try to subvert the nonce file (this assumes noncefile is the last key/value pair)
1157 address = g_dbus_server_get_client_address (server);
1159 s = strstr (address, "noncefile=");
1160 g_assert (s != NULL);
1161 s += sizeof "noncefile=" - 1;
1162 nonce_file = g_strdup (s);
1164 /* First try invalid data in the nonce file - this will actually
1165 * make the client send this and the server will reject it. The way
1166 * it works is that if the nonce doesn't match, the server will
1167 * simply close the connection. So, from the client point of view,
1168 * we can see a variety of errors.
1171 res = g_file_set_contents (nonce_file,
1175 g_assert_no_error (error);
1177 c = g_dbus_connection_new_for_address_sync (address,
1178 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1179 NULL, /* GDBusAuthObserver */
1180 NULL, /* cancellable */
1182 _g_assert_error_domain (error, G_IO_ERROR);
1183 g_assert (c == NULL);
1185 /* Then try with a nonce-file of incorrect length - this will make
1186 * the client complain - we won't even try connecting to the server
1190 res = g_file_set_contents (nonce_file,
1191 "0123456789012345_",
1194 g_assert_no_error (error);
1196 c = g_dbus_connection_new_for_address_sync (address,
1197 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1198 NULL, /* GDBusAuthObserver */
1199 NULL, /* cancellable */
1201 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1202 g_assert (c == NULL);
1204 /* Finally try with no nonce-file at all */
1205 g_assert_cmpint (g_unlink (nonce_file), ==, 0);
1207 c = g_dbus_connection_new_for_address_sync (address,
1208 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1209 NULL, /* GDBusAuthObserver */
1210 NULL, /* cancellable */
1212 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1213 g_assert (c == NULL);
1215 g_free (nonce_file);
1217 g_dbus_server_stop (server);
1218 g_object_unref (server);
1221 g_main_loop_quit (service_loop);
1222 g_thread_join (service_thread);
1226 test_credentials (void)
1228 GCredentials *c1, *c2;
1232 c1 = g_credentials_new ();
1233 c2 = g_credentials_new ();
1236 if (g_credentials_set_unix_user (c2, getuid (), &error))
1237 g_assert_no_error (error);
1239 g_clear_error (&error);
1240 g_assert (g_credentials_is_same_user (c1, c2, &error));
1241 g_assert_no_error (error);
1243 desc = g_credentials_to_string (c1);
1244 g_assert (desc != NULL);
1247 g_object_unref (c1);
1248 g_object_unref (c2);
1251 /* ---------------------------------------------------------------------------------------------------- */
1255 /* Chosen to be big enough to overflow the socket buffer */
1256 #define OVERFLOW_NUM_SIGNALS 5000
1257 #define OVERFLOW_TIMEOUT_SEC 10
1260 overflow_filter_func (GDBusConnection *connection,
1261 GDBusMessage *message,
1265 volatile gint *counter = user_data;
1267 return FALSE; /* don't drop the message */
1271 overflow_on_500ms_later_func (gpointer user_data)
1273 g_main_loop_quit (loop);
1274 return FALSE; /* don't keep the idle */
1278 test_overflow (void)
1283 GSocketConnection *socket_connection;
1284 GDBusConnection *producer, *consumer;
1287 volatile gint n_messages_received;
1288 volatile gint n_messages_sent;
1290 g_assert_cmpint (socketpair (AF_UNIX, SOCK_STREAM, 0, sv), ==, 0);
1293 socket = g_socket_new_from_fd (sv[0], &error);
1294 g_assert_no_error (error);
1295 socket_connection = g_socket_connection_factory_create_connection (socket);
1296 g_assert (socket_connection != NULL);
1297 g_object_unref (socket);
1298 producer = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
1300 G_DBUS_CONNECTION_FLAGS_NONE,
1301 NULL, /* GDBusAuthObserver */
1302 NULL, /* GCancellable */
1304 g_dbus_connection_set_exit_on_close (producer, TRUE);
1305 g_assert_no_error (error);
1306 g_object_unref (socket_connection);
1307 n_messages_sent = 0;
1308 g_dbus_connection_add_filter (producer, overflow_filter_func, (gpointer) &n_messages_sent, NULL);
1310 /* send enough data that we get an EAGAIN */
1311 for (n = 0; n < OVERFLOW_NUM_SIGNALS; n++)
1314 g_dbus_connection_emit_signal (producer,
1315 NULL, /* destination */
1317 "org.foo.Interface",
1319 g_variant_new ("(s)", "a string"),
1321 g_assert_no_error (error);
1324 /* sleep for 0.5 sec (to allow the GDBus IO thread to fill up the
1325 * kernel buffers) and verify that n_messages_sent <
1326 * OVERFLOW_NUM_SIGNALS
1328 * This is to verify that not all the submitted messages have been
1329 * sent to the underlying transport.
1331 g_timeout_add (500, overflow_on_500ms_later_func, NULL);
1332 g_main_loop_run (loop);
1333 g_assert_cmpint (n_messages_sent, <, OVERFLOW_NUM_SIGNALS);
1335 /* now suck it all out as a client, and add it up */
1336 socket = g_socket_new_from_fd (sv[1], &error);
1337 g_assert_no_error (error);
1338 socket_connection = g_socket_connection_factory_create_connection (socket);
1339 g_assert (socket_connection != NULL);
1340 g_object_unref (socket);
1341 consumer = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
1343 G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
1344 NULL, /* GDBusAuthObserver */
1345 NULL, /* GCancellable */
1347 g_assert_no_error (error);
1348 g_object_unref (socket_connection);
1349 n_messages_received = 0;
1350 g_dbus_connection_add_filter (consumer, overflow_filter_func, (gpointer) &n_messages_received, NULL);
1351 g_dbus_connection_start_message_processing (consumer);
1353 timer = g_timer_new ();
1354 g_timer_start (timer);
1356 while (n_messages_received < OVERFLOW_NUM_SIGNALS && g_timer_elapsed (timer, NULL) < OVERFLOW_TIMEOUT_SEC)
1357 g_main_context_iteration (NULL, FALSE);
1359 g_assert_cmpint (n_messages_sent, ==, OVERFLOW_NUM_SIGNALS);
1360 g_assert_cmpint (n_messages_received, ==, OVERFLOW_NUM_SIGNALS);
1362 g_timer_destroy (timer);
1363 g_object_unref (consumer);
1364 g_object_unref (producer);
1368 test_overflow (void)
1370 /* TODO: test this with e.g. GWin32InputStream/GWin32OutputStream */
1374 /* ---------------------------------------------------------------------------------------------------- */
1381 GDBusNodeInfo *introspection_data = NULL;
1384 g_thread_init (NULL);
1385 g_test_init (&argc, &argv, NULL);
1387 introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
1388 g_assert (introspection_data != NULL);
1389 test_interface_introspection_data = introspection_data->interfaces[0];
1391 test_guid = g_dbus_generate_guid ();
1393 /* all the tests rely on a shared main loop */
1394 loop = g_main_loop_new (NULL, FALSE);
1396 g_test_add_func ("/gdbus/peer-to-peer", test_peer);
1397 g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing);
1398 g_test_add_func ("/gdbus/nonce-tcp", test_nonce_tcp);
1399 g_test_add_func ("/gdbus/credentials", test_credentials);
1400 g_test_add_func ("/gdbus/overflow", test_overflow);
1404 g_main_loop_unref (loop);
1406 g_dbus_node_info_unref (introspection_data);