mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-01 00:42:16 +01:00 
			
		
		
		
	Most D-Bus interfaces are domain-specific, but these interfaces from the D-Bus Specification are intended to be commonly used in any context for which they are found to be appropriate. Most of these use `gdbusprivate.h`. One exception is that `gio/tests/gdbus-example-*` redefine the constants locally: due to these files' dual role as part of the unit tests and as sample code, it seems desirable to ensure that they can still be compiled outside GLib. Signed-off-by: Simon McVittie <smcv@collabora.com>
		
			
				
	
	
		
			2268 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2268 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GLib testing framework examples and tests
 | |
|  *
 | |
|  * Copyright (C) 2008-2010 Red Hat, Inc.
 | |
|  *
 | |
|  * SPDX-License-Identifier: LGPL-2.1-or-later
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2.1 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General
 | |
|  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | |
|  *
 | |
|  * Author: David Zeuthen <davidz@redhat.com>
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include <gio/gio.h>
 | |
| #include <string.h>
 | |
| 
 | |
| /* for open(2) */
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <string.h>
 | |
| 
 | |
| /* for g_unlink() */
 | |
| #include <glib/gstdio.h>
 | |
| 
 | |
| #include <gio/gnetworking.h>
 | |
| #include <gio/gunixsocketaddress.h>
 | |
| #include <gio/gunixfdlist.h>
 | |
| #include <gio/gcredentialsprivate.h>
 | |
| 
 | |
| #ifdef G_OS_UNIX
 | |
| #include <gio/gunixconnection.h>
 | |
| #include <errno.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef G_OS_WIN32
 | |
| #include <gio/giowin32-afunix.h>
 | |
| #endif
 | |
| 
 | |
| #include "gdbusprivate.h"
 | |
| #include "gdbus-tests.h"
 | |
| 
 | |
| #include "gdbus-object-manager-example/objectmanager-gen.h"
 | |
| 
 | |
| #ifdef G_OS_UNIX
 | |
| static gboolean is_unix = TRUE;
 | |
| #else
 | |
| static gboolean is_unix = FALSE;
 | |
| #endif
 | |
| 
 | |
| static gchar *tmpdir = NULL;
 | |
| static gchar *tmp_address = NULL;
 | |
| static gchar *test_guid = NULL;
 | |
| static GMutex service_loop_lock;
 | |
| static GCond service_loop_cond;
 | |
| static GMainLoop *service_loop = NULL;
 | |
| static GDBusServer *server = NULL;
 | |
| static GMainLoop *loop = NULL;
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| /* Test that peer-to-peer connections work */
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   gboolean accept_connection;
 | |
|   gint num_connection_attempts;
 | |
|   GPtrArray *current_connections;
 | |
|   guint num_method_calls;
 | |
|   gboolean signal_received;
 | |
| } PeerData;
 | |
| 
 | |
| /* This needs to be enough to usually take more than one write(),
 | |
|  * to reproduce
 | |
|  * <https://gitlab.gnome.org/GNOME/glib/-/issues/2074>.
 | |
|  * 1 MiB ought to be enough. */
 | |
| #define BIG_MESSAGE_ARRAY_SIZE (1024 * 1024)
 | |
| 
 | |
| static const gchar *test_interface_introspection_xml =
 | |
|   "<node>"
 | |
|   "  <interface name='org.gtk.GDBus.PeerTestInterface'>"
 | |
|   "    <method name='HelloPeer'>"
 | |
|   "      <arg type='s' name='greeting' direction='in'/>"
 | |
|   "      <arg type='s' name='response' direction='out'/>"
 | |
|   "    </method>"
 | |
|   "    <method name='EmitSignal'/>"
 | |
|   "    <method name='EmitSignalWithNameSet'/>"
 | |
|   "    <method name='OpenFile'>"
 | |
|   "      <arg type='s' name='path' direction='in'/>"
 | |
|   "    </method>"
 | |
|   "    <method name='OpenFileWithBigMessage'>"
 | |
|   "      <arg type='s' name='path' direction='in'/>"
 | |
|   "      <arg type='h' name='handle' direction='out'/>"
 | |
|   "      <arg type='ay' name='junk' direction='out'/>"
 | |
|   "    </method>"
 | |
|   "    <signal name='PeerSignal'>"
 | |
|   "      <arg type='s' name='a_string'/>"
 | |
|   "    </signal>"
 | |
|   "    <property type='s' name='PeerProperty' access='read'/>"
 | |
|   "  </interface>"
 | |
|   "</node>";
 | |
| static GDBusInterfaceInfo *test_interface_introspection_data = NULL;
 | |
| 
 | |
| static void
 | |
| test_interface_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)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
|   const GDBusMethodInfo *info;
 | |
| 
 | |
|   data->num_method_calls++;
 | |
| 
 | |
|   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
 | |
|   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
 | |
| 
 | |
|   info = g_dbus_method_invocation_get_method_info (invocation);
 | |
|   g_assert_cmpstr (info->name, ==, method_name);
 | |
| 
 | |
|   if (g_strcmp0 (method_name, "HelloPeer") == 0)
 | |
|     {
 | |
|       const gchar *greeting;
 | |
|       gchar *response;
 | |
| 
 | |
|       g_variant_get (parameters, "(&s)", &greeting);
 | |
| 
 | |
|       response = g_strdup_printf ("You greeted me with '%s'.",
 | |
|                                   greeting);
 | |
|       g_dbus_method_invocation_return_value (invocation,
 | |
|                                              g_variant_new ("(s)", response));
 | |
|       g_free (response);
 | |
|     }
 | |
|   else if (g_strcmp0 (method_name, "EmitSignal") == 0)
 | |
|     {
 | |
|       GError *error;
 | |
| 
 | |
|       error = NULL;
 | |
|       g_dbus_connection_emit_signal (connection,
 | |
|                                      NULL,
 | |
|                                      "/org/gtk/GDBus/PeerTestObject",
 | |
|                                      "org.gtk.GDBus.PeerTestInterface",
 | |
|                                      "PeerSignal",
 | |
|                                      NULL,
 | |
|                                      &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_dbus_method_invocation_return_value (invocation, NULL);
 | |
|     }
 | |
|   else if (g_strcmp0 (method_name, "EmitSignalWithNameSet") == 0)
 | |
|     {
 | |
|       GError *error;
 | |
|       gboolean ret;
 | |
|       GDBusMessage *message;
 | |
| 
 | |
|       message = g_dbus_message_new_signal ("/org/gtk/GDBus/PeerTestObject",
 | |
|                                            "org.gtk.GDBus.PeerTestInterface",
 | |
|                                            "PeerSignalWithNameSet");
 | |
|       g_dbus_message_set_sender (message, ":1.42");
 | |
| 
 | |
|       error = NULL;
 | |
|       ret = g_dbus_connection_send_message (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_assert (ret);
 | |
|       g_object_unref (message);
 | |
| 
 | |
|       g_dbus_method_invocation_return_value (invocation, NULL);
 | |
|     }
 | |
|   else if (g_strcmp0 (method_name, "OpenFile") == 0 ||
 | |
|            g_strcmp0 (method_name, "OpenFileWithBigMessage") == 0)
 | |
|     {
 | |
| #ifdef G_OS_UNIX
 | |
|       const gchar *path;
 | |
|       GDBusMessage *reply;
 | |
|       GError *error;
 | |
|       gint fd;
 | |
|       GUnixFDList *fd_list;
 | |
| 
 | |
|       g_variant_get (parameters, "(&s)", &path);
 | |
| 
 | |
|       fd_list = g_unix_fd_list_new ();
 | |
| 
 | |
|       error = NULL;
 | |
| 
 | |
|       fd = g_open (path, O_RDONLY, 0);
 | |
|       g_assert (fd != -1);
 | |
|       g_unix_fd_list_append (fd_list, fd, &error);
 | |
|       g_assert_no_error (error);
 | |
|       close (fd);
 | |
| 
 | |
|       reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
 | |
|       g_dbus_message_set_unix_fd_list (reply, fd_list);
 | |
|       g_object_unref (fd_list);
 | |
|       g_object_unref (invocation);
 | |
| 
 | |
|       if (g_strcmp0 (method_name, "OpenFileWithBigMessage") == 0)
 | |
|         {
 | |
|           char *junk;
 | |
| 
 | |
|           junk = g_new0 (char, BIG_MESSAGE_ARRAY_SIZE);
 | |
|           g_dbus_message_set_body (reply,
 | |
|                                    g_variant_new ("(h@ay)",
 | |
|                                                   0,
 | |
|                                                   g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
 | |
|                                                                              junk,
 | |
|                                                                              BIG_MESSAGE_ARRAY_SIZE,
 | |
|                                                                              1)));
 | |
|           g_free (junk);
 | |
|         }
 | |
| 
 | |
|       error = NULL;
 | |
|       g_dbus_connection_send_message (connection,
 | |
|                                       reply,
 | |
|                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
 | |
|                                       NULL, /* out_serial */
 | |
|                                       &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_object_unref (reply);
 | |
| #else
 | |
|       g_dbus_method_invocation_return_dbus_error (invocation,
 | |
|                                                   "org.gtk.GDBus.NotOnUnix",
 | |
|                                                   "Your OS does not support file descriptor passing");
 | |
| #endif
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_assert_not_reached ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| static GVariant *
 | |
| test_interface_get_property (GDBusConnection  *connection,
 | |
|                              const gchar      *sender,
 | |
|                              const gchar      *object_path,
 | |
|                              const gchar      *interface_name,
 | |
|                              const gchar      *property_name,
 | |
|                              GError          **error,
 | |
|                              gpointer          user_data)
 | |
| {
 | |
|   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
 | |
|   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
 | |
|   g_assert_cmpstr (property_name, ==, "PeerProperty");
 | |
| 
 | |
|   return g_variant_new_string ("ThePropertyValue");
 | |
| }
 | |
| 
 | |
| 
 | |
| static const GDBusInterfaceVTable test_interface_vtable =
 | |
| {
 | |
|   test_interface_method_call,
 | |
|   test_interface_get_property,
 | |
|   NULL,  /* set_property */
 | |
|   { 0 }
 | |
| };
 | |
| 
 | |
| static void
 | |
| on_proxy_signal_received (GDBusProxy *proxy,
 | |
|                           gchar      *sender_name,
 | |
|                           gchar      *signal_name,
 | |
|                           GVariant   *parameters,
 | |
|                           gpointer    user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
| 
 | |
|   data->signal_received = TRUE;
 | |
| 
 | |
|   g_assert (sender_name == NULL);
 | |
|   g_assert_cmpstr (signal_name, ==, "PeerSignal");
 | |
|   g_main_loop_quit (loop);
 | |
| }
 | |
| 
 | |
| static void
 | |
| on_proxy_signal_received_with_name_set (GDBusProxy *proxy,
 | |
|                                         gchar      *sender_name,
 | |
|                                         gchar      *signal_name,
 | |
|                                         GVariant   *parameters,
 | |
|                                         gpointer    user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
| 
 | |
|   data->signal_received = TRUE;
 | |
| 
 | |
|   g_assert_cmpstr (sender_name, ==, ":1.42");
 | |
|   g_assert_cmpstr (signal_name, ==, "PeerSignalWithNameSet");
 | |
|   g_main_loop_quit (loop);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static gboolean
 | |
| af_unix_works (void)
 | |
| {
 | |
|   int fd;
 | |
| 
 | |
|   g_networking_init ();
 | |
|   fd = socket (AF_UNIX, SOCK_STREAM, 0);
 | |
| 
 | |
| #ifdef G_OS_WIN32
 | |
|   closesocket (fd);
 | |
|   return fd != (int) INVALID_SOCKET;
 | |
| #else
 | |
|   g_close (fd, NULL);
 | |
|   return fd >= 0;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void
 | |
| setup_test_address (void)
 | |
| {
 | |
|   if (is_unix || af_unix_works ())
 | |
|     {
 | |
|       g_test_message ("Testing with unix:dir address");
 | |
|       tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
 | |
|       tmp_address = g_strdup_printf ("unix:dir=%s", tmpdir);
 | |
|     }
 | |
|   else
 | |
|     tmp_address = g_strdup ("nonce-tcp:host=127.0.0.1");
 | |
| }
 | |
| 
 | |
| #ifdef G_OS_UNIX
 | |
| static void
 | |
| setup_tmpdir_test_address (void)
 | |
| {
 | |
|   g_test_message ("Testing with unix:tmpdir address");
 | |
|   tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
 | |
|   tmp_address = g_strdup_printf ("unix:tmpdir=%s", tmpdir);
 | |
| }
 | |
| 
 | |
| static void
 | |
| setup_path_test_address (void)
 | |
| {
 | |
|   g_test_message ("Testing with unix:path address");
 | |
|   tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
 | |
|   tmp_address = g_strdup_printf ("unix:path=%s/gdbus-peer-socket", tmpdir);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void
 | |
| teardown_test_address (void)
 | |
| {
 | |
|   g_free (tmp_address);
 | |
|   if (tmpdir)
 | |
|     {
 | |
|       /* Ensuring the rmdir succeeds also ensures any sockets created on the
 | |
|        * filesystem are also deleted.
 | |
|        */
 | |
|       g_assert_cmpstr (g_rmdir (tmpdir) == 0 ? "OK" : g_strerror (errno),
 | |
|                        ==, "OK");
 | |
|       g_clear_pointer (&tmpdir, g_free);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static gboolean
 | |
| on_authorize_authenticated_peer (GDBusAuthObserver *observer,
 | |
|                                  GIOStream         *stream,
 | |
|                                  GCredentials      *credentials,
 | |
|                                  gpointer           user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
|   gboolean authorized;
 | |
| 
 | |
|   data->num_connection_attempts++;
 | |
| 
 | |
|   authorized = TRUE;
 | |
|   if (!data->accept_connection)
 | |
|     {
 | |
|       authorized = FALSE;
 | |
|       g_main_loop_quit (loop);
 | |
|     }
 | |
| 
 | |
|   return authorized;
 | |
| }
 | |
| 
 | |
| /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
 | |
| static gboolean
 | |
| on_new_connection (GDBusServer *server,
 | |
|                    GDBusConnection *connection,
 | |
|                    gpointer user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
|   GError *error = NULL;
 | |
|   guint reg_id;
 | |
| 
 | |
|   //g_printerr ("Client connected.\n"
 | |
|   //         "Negotiated capabilities: unix-fd-passing=%d\n",
 | |
|   //         g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
 | |
| 
 | |
|   g_ptr_array_add (data->current_connections, g_object_ref (connection));
 | |
| 
 | |
| #if G_CREDENTIALS_SUPPORTED
 | |
|     {
 | |
|       GCredentials *credentials;
 | |
| 
 | |
|       credentials = g_dbus_connection_get_peer_credentials (connection);
 | |
| 
 | |
|       g_assert (credentials != NULL);
 | |
| #ifdef G_OS_WIN32
 | |
|       {
 | |
|         DWORD *pid;
 | |
|         pid = g_credentials_get_native (credentials, G_CREDENTIALS_TYPE_WIN32_PID);
 | |
|         g_assert_cmpuint (*pid, ==, GetCurrentProcessId ());
 | |
|       }
 | |
| #else
 | |
|       g_assert_cmpuint (g_credentials_get_unix_user (credentials, NULL), ==,
 | |
|                         getuid ());
 | |
| #if G_CREDENTIALS_HAS_PID
 | |
|       g_assert_cmpint (g_credentials_get_unix_pid (credentials, &error), ==,
 | |
|                        getpid ());
 | |
|       g_assert_no_error (error);
 | |
| #else
 | |
|       g_assert_cmpint (g_credentials_get_unix_pid (credentials, &error), ==, -1);
 | |
|       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
 | |
|       g_clear_error (&error);
 | |
| #endif /* G_CREDENTIALS_HAS_PID */
 | |
| #endif /* G_OS_WIN32 */
 | |
|     }
 | |
| #endif /* G_CREDENTIALS_SUPPORTED */
 | |
| 
 | |
|   /* export object on the newly established connection */
 | |
|   reg_id = g_dbus_connection_register_object (connection,
 | |
|                                               "/org/gtk/GDBus/PeerTestObject",
 | |
|                                               test_interface_introspection_data,
 | |
|                                               &test_interface_vtable,
 | |
|                                               data,
 | |
|                                               NULL, /* GDestroyNotify for data */
 | |
|                                               &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (reg_id > 0);
 | |
| 
 | |
|   g_main_loop_quit (loop);
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /* We don't tell the main thread about the new GDBusServer until it has
 | |
|  * had a chance to start listening. */
 | |
| static gboolean
 | |
| idle_in_service_loop (gpointer loop)
 | |
| {
 | |
|   g_assert (service_loop == NULL);
 | |
|   g_mutex_lock (&service_loop_lock);
 | |
|   service_loop = loop;
 | |
|   g_cond_broadcast (&service_loop_cond);
 | |
|   g_mutex_unlock (&service_loop_lock);
 | |
| 
 | |
|   return G_SOURCE_REMOVE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| run_service_loop (GMainContext *service_context)
 | |
| {
 | |
|   GMainLoop *loop;
 | |
|   GSource *source;
 | |
| 
 | |
|   g_assert (service_loop == NULL);
 | |
| 
 | |
|   loop = g_main_loop_new (service_context, FALSE);
 | |
|   source = g_idle_source_new ();
 | |
|   g_source_set_callback (source, idle_in_service_loop, loop, NULL);
 | |
|   g_source_attach (source, service_context);
 | |
|   g_source_unref (source);
 | |
|   g_main_loop_run (loop);
 | |
| }
 | |
| 
 | |
| static void
 | |
| teardown_service_loop (void)
 | |
| {
 | |
|   g_mutex_lock (&service_loop_lock);
 | |
|   g_clear_pointer (&service_loop, g_main_loop_unref);
 | |
|   g_mutex_unlock (&service_loop_lock);
 | |
| }
 | |
| 
 | |
| static void
 | |
| await_service_loop (void)
 | |
| {
 | |
|   g_mutex_lock (&service_loop_lock);
 | |
|   while (service_loop == NULL)
 | |
|     g_cond_wait (&service_loop_cond, &service_loop_lock);
 | |
|   g_mutex_unlock (&service_loop_lock);
 | |
| }
 | |
| 
 | |
| static gpointer
 | |
| service_thread_func (gpointer user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
|   GMainContext *service_context;
 | |
|   GDBusAuthObserver *observer, *o;
 | |
|   GError *error;
 | |
|   GDBusServerFlags f;
 | |
|   gchar *a, *g;
 | |
|   gboolean b;
 | |
| 
 | |
|   service_context = g_main_context_new ();
 | |
|   g_main_context_push_thread_default (service_context);
 | |
| 
 | |
|   error = NULL;
 | |
|   observer = g_dbus_auth_observer_new ();
 | |
|   server = g_dbus_server_new_sync (tmp_address,
 | |
|                                    G_DBUS_SERVER_FLAGS_NONE,
 | |
|                                    test_guid,
 | |
|                                    observer,
 | |
|                                    NULL, /* cancellable */
 | |
|                                    &error);
 | |
|   g_assert_no_error (error);
 | |
| 
 | |
|   g_signal_connect (server,
 | |
|                     "new-connection",
 | |
|                     G_CALLBACK (on_new_connection),
 | |
|                     data);
 | |
|   g_signal_connect (observer,
 | |
|                     "authorize-authenticated-peer",
 | |
|                     G_CALLBACK (on_authorize_authenticated_peer),
 | |
|                     data);
 | |
| 
 | |
|   g_assert_cmpint (g_dbus_server_get_flags (server), ==, G_DBUS_SERVER_FLAGS_NONE);
 | |
|   g_assert_cmpstr (g_dbus_server_get_guid (server), ==, test_guid);
 | |
|   g_object_get (server,
 | |
|                 "flags", &f,
 | |
|                 "address", &a,
 | |
|                 "guid", &g,
 | |
|                 "active", &b,
 | |
|                 "authentication-observer", &o,
 | |
|                 NULL);
 | |
|   g_assert_cmpint (f, ==, G_DBUS_SERVER_FLAGS_NONE);
 | |
|   g_assert_cmpstr (a, ==, tmp_address);
 | |
|   g_assert_cmpstr (g, ==, test_guid);
 | |
|   g_assert (!b);
 | |
|   g_assert (o == observer);
 | |
|   g_free (a);
 | |
|   g_free (g);
 | |
|   g_object_unref (o);
 | |
| 
 | |
|   g_object_unref (observer);
 | |
| 
 | |
|   g_dbus_server_start (server);
 | |
| 
 | |
|   run_service_loop (service_context);
 | |
| 
 | |
|   g_main_context_pop_thread_default (service_context);
 | |
| 
 | |
|   teardown_service_loop ();
 | |
|   g_main_context_unref (service_context);
 | |
| 
 | |
|   /* test code specifically unrefs the server - see below */
 | |
|   g_assert (server == NULL);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| static gboolean
 | |
| on_incoming_connection (GSocketService     *service,
 | |
|                         GSocketConnection  *socket_connection,
 | |
|                         GObject            *source_object,
 | |
|                         gpointer           user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
| 
 | |
|   if (data->accept_connection)
 | |
|     {
 | |
|       GError *error;
 | |
|       guint reg_id;
 | |
|       GDBusConnection *connection;
 | |
| 
 | |
|       error = NULL;
 | |
|       connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
 | |
|                                                test_guid,
 | |
|                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
 | |
|                                                NULL, /* cancellable */
 | |
|                                                &error);
 | |
|       g_assert_no_error (error);
 | |
| 
 | |
|       g_ptr_array_add (data->current_connections, connection);
 | |
| 
 | |
|       /* export object on the newly established connection */
 | |
|       error = NULL;
 | |
|       reg_id = g_dbus_connection_register_object (connection,
 | |
|                                                   "/org/gtk/GDBus/PeerTestObject",
 | |
|                                                   &test_interface_introspection_data,
 | |
|                                                   &test_interface_vtable,
 | |
|                                                   data,
 | |
|                                                   NULL, /* GDestroyNotify for data */
 | |
|                                                   &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_assert (reg_id > 0);
 | |
| 
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* don't do anything */
 | |
|     }
 | |
| 
 | |
|   data->num_connection_attempts++;
 | |
| 
 | |
|   g_main_loop_quit (loop);
 | |
| 
 | |
|   /* stops other signal handlers from being invoked */
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static gpointer
 | |
| service_thread_func (gpointer data)
 | |
| {
 | |
|   GMainContext *service_context;
 | |
|   gchar *socket_path;
 | |
|   GSocketAddress *address;
 | |
|   GError *error;
 | |
| 
 | |
|   service_context = g_main_context_new ();
 | |
|   g_main_context_push_thread_default (service_context);
 | |
| 
 | |
|   socket_path = g_strdup_printf ("/tmp/gdbus-test-pid-%d", getpid ());
 | |
|   address = g_unix_socket_address_new (socket_path);
 | |
| 
 | |
|   service = g_socket_service_new ();
 | |
|   error = NULL;
 | |
|   g_socket_listener_add_address (G_SOCKET_LISTENER (service),
 | |
|                                  address,
 | |
|                                  G_SOCKET_TYPE_STREAM,
 | |
|                                  G_SOCKET_PROTOCOL_DEFAULT,
 | |
|                                  NULL, /* source_object */
 | |
|                                  NULL, /* effective_address */
 | |
|                                  &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_signal_connect (service,
 | |
|                     "incoming",
 | |
|                     G_CALLBACK (on_incoming_connection),
 | |
|                     data);
 | |
|   g_socket_service_start (service);
 | |
| 
 | |
|   run_service_loop (service_context);
 | |
| 
 | |
|   g_main_context_pop_thread_default (service_context);
 | |
| 
 | |
|   teardown_service_loop ();
 | |
|   g_main_context_unref (service_context);
 | |
| 
 | |
|   g_object_unref (address);
 | |
|   g_free (socket_path);
 | |
|   return NULL;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| #if 0
 | |
| static gboolean
 | |
| check_connection (gpointer user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
|   guint n;
 | |
| 
 | |
|   for (n = 0; n < data->current_connections->len; n++)
 | |
|     {
 | |
|       GDBusConnection *c;
 | |
|       GIOStream *stream;
 | |
| 
 | |
|       c = G_DBUS_CONNECTION (data->current_connections->pdata[n]);
 | |
|       stream = g_dbus_connection_get_stream (c);
 | |
| 
 | |
|       g_debug ("In check_connection for %d: connection %p, stream %p", n, c, stream);
 | |
|       g_debug ("closed = %d", g_io_stream_is_closed (stream));
 | |
| 
 | |
|       GSocket *socket;
 | |
|       socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
 | |
|       g_debug ("socket_closed = %d", g_socket_is_closed (socket));
 | |
|       g_debug ("socket_condition_check = %d", g_socket_condition_check (socket, G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP));
 | |
| 
 | |
|       gchar buf[128];
 | |
|       GError *error;
 | |
|       gssize num_read;
 | |
|       error = NULL;
 | |
|       num_read = g_input_stream_read (g_io_stream_get_input_stream (stream),
 | |
|                                       buf,
 | |
|                                       128,
 | |
|                                       NULL,
 | |
|                                       &error);
 | |
|       if (num_read < 0)
 | |
|         {
 | |
|           g_debug ("error: %s", error->message);
 | |
|           g_error_free (error);
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           g_debug ("no error, read %d bytes", (gint) num_read);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   return G_SOURCE_REMOVE;
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| on_do_disconnect_in_idle (gpointer data)
 | |
| {
 | |
|   GDBusConnection *c = G_DBUS_CONNECTION (data);
 | |
|   g_debug ("GDC %p has ref_count %d", c, G_OBJECT (c)->ref_count);
 | |
|   g_dbus_connection_disconnect (c);
 | |
|   g_object_unref (c);
 | |
|   return G_SOURCE_REMOVE;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef G_OS_UNIX
 | |
| static gchar *
 | |
| read_all_from_fd (gint fd, gsize *out_len, GError **error)
 | |
| {
 | |
|   GString *str;
 | |
|   gchar buf[64];
 | |
|   gssize num_read;
 | |
| 
 | |
|   str = g_string_new (NULL);
 | |
| 
 | |
|   do
 | |
|     {
 | |
|       int errsv;
 | |
| 
 | |
|       num_read = read (fd, buf, sizeof (buf));
 | |
|       errsv = errno;
 | |
|       if (num_read == -1)
 | |
|         {
 | |
|           if (errsv == EAGAIN || errsv == EWOULDBLOCK)
 | |
|             continue;
 | |
|           g_set_error (error,
 | |
|                        G_IO_ERROR,
 | |
|                        g_io_error_from_errno (errsv),
 | |
|                        "Failed reading %d bytes into offset %d: %s",
 | |
|                        (gint) sizeof (buf),
 | |
|                        (gint) str->len,
 | |
|                        g_strerror (errsv));
 | |
|           goto error;
 | |
|         }
 | |
|       else if (num_read > 0)
 | |
|         {
 | |
|           g_string_append_len (str, buf, num_read);
 | |
|         }
 | |
|       else if (num_read == 0)
 | |
|         {
 | |
|           break;
 | |
|         }
 | |
|     }
 | |
|   while (TRUE);
 | |
| 
 | |
|   if (out_len != NULL)
 | |
|     *out_len = str->len;
 | |
|   return g_string_free (str, FALSE);
 | |
| 
 | |
|  error:
 | |
|   if (out_len != NULL)
 | |
|     *out_len = 0;
 | |
|   g_string_free (str, TRUE);
 | |
|   return NULL;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void
 | |
| do_test_peer (void)
 | |
| {
 | |
|   GDBusConnection *c;
 | |
|   GDBusConnection *c2;
 | |
|   GDBusProxy *proxy;
 | |
|   GError *error;
 | |
|   PeerData data;
 | |
|   GVariant *value;
 | |
|   GVariant *result;
 | |
|   const gchar *s;
 | |
|   GThread *service_thread;
 | |
|   gulong signal_handler_id;
 | |
|   gsize i;
 | |
| 
 | |
|   memset (&data, '\0', sizeof (PeerData));
 | |
|   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
 | |
| 
 | |
|   /* first try to connect when there is no server */
 | |
|   error = NULL;
 | |
|   c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" :
 | |
|                                               /* NOTE: Even if something is listening on port 12345 the connection
 | |
|                                                * will fail because the nonce file doesn't exist */
 | |
|                                               "nonce-tcp:host=127.0.0.1,port=12345,noncefile=this-does-not-exist-gdbus",
 | |
|                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                               NULL, /* GDBusAuthObserver */
 | |
|                                               NULL, /* cancellable */
 | |
|                                               &error);
 | |
|   _g_assert_error_domain (error, G_IO_ERROR);
 | |
|   g_assert (!g_dbus_error_is_remote_error (error));
 | |
|   g_clear_error (&error);
 | |
|   g_assert (c == NULL);
 | |
| 
 | |
|   /* bring up a server - we run the server in a different thread to avoid deadlocks */
 | |
|   service_thread = g_thread_new ("test_peer",
 | |
|                                  service_thread_func,
 | |
|                                  &data);
 | |
|   await_service_loop ();
 | |
|   g_assert (server != NULL);
 | |
| 
 | |
|   /* bring up a connection and accept it */
 | |
|   data.accept_connection = TRUE;
 | |
|   error = NULL;
 | |
|   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
 | |
|                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                               NULL, /* GDBusAuthObserver */
 | |
|                                               NULL, /* cancellable */
 | |
|                                               &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (c != NULL);
 | |
|   while (data.current_connections->len < 1)
 | |
|     g_main_loop_run (loop);
 | |
|   g_assert_cmpint (data.current_connections->len, ==, 1);
 | |
|   g_assert_cmpint (data.num_connection_attempts, ==, 1);
 | |
|   g_assert (g_dbus_connection_get_unique_name (c) == NULL);
 | |
|   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
 | |
| 
 | |
|   /* check that we create a proxy, read properties, receive signals and invoke
 | |
|    * the HelloPeer() method. Since the server runs in another thread it's fine
 | |
|    * to use synchronous blocking API here.
 | |
|    */
 | |
|   error = NULL;
 | |
|   proxy = g_dbus_proxy_new_sync (c,
 | |
|                                  G_DBUS_PROXY_FLAGS_NONE,
 | |
|                                  NULL,
 | |
|                                  NULL, /* bus_name */
 | |
|                                  "/org/gtk/GDBus/PeerTestObject",
 | |
|                                  "org.gtk.GDBus.PeerTestInterface",
 | |
|                                  NULL, /* GCancellable */
 | |
|                                  &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (proxy != NULL);
 | |
|   error = NULL;
 | |
|   value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
 | |
|   g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
 | |
|   g_clear_pointer (&value, g_variant_unref);
 | |
| 
 | |
|   /* try invoking a method */
 | |
|   error = NULL;
 | |
|   result = g_dbus_proxy_call_sync (proxy,
 | |
|                                    "HelloPeer",
 | |
|                                    g_variant_new ("(s)", "Hey Peer!"),
 | |
|                                    G_DBUS_CALL_FLAGS_NONE,
 | |
|                                    -1,
 | |
|                                    NULL,  /* GCancellable */
 | |
|                                    &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_variant_get (result, "(&s)", &s);
 | |
|   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Peer!'.");
 | |
|   g_variant_unref (result);
 | |
|   g_assert_cmpint (data.num_method_calls, ==, 1);
 | |
| 
 | |
|   /* make the other peer emit a signal - catch it */
 | |
|   signal_handler_id = g_signal_connect (proxy,
 | |
|                                         "g-signal",
 | |
|                                         G_CALLBACK (on_proxy_signal_received),
 | |
|                                         &data);
 | |
|   g_assert (!data.signal_received);
 | |
|   g_dbus_proxy_call (proxy,
 | |
|                      "EmitSignal",
 | |
|                      NULL,  /* no arguments */
 | |
|                      G_DBUS_CALL_FLAGS_NONE,
 | |
|                      -1,
 | |
|                      NULL,  /* GCancellable */
 | |
|                      NULL,  /* GAsyncReadyCallback - we don't care about the result */
 | |
|                      NULL); /* user_data */
 | |
|   g_main_loop_run (loop);
 | |
|   g_assert (data.signal_received);
 | |
|   g_assert_cmpint (data.num_method_calls, ==, 2);
 | |
|   g_signal_handler_disconnect (proxy, signal_handler_id);
 | |
| 
 | |
|   /* Also ensure that messages with the sender header-field set gets
 | |
|    * delivered to the proxy - note that this doesn't really make sense
 | |
|    * e.g. names are meaning-less in a peer-to-peer case... but we
 | |
|    * support it because it makes sense in certain bridging
 | |
|    * applications - see e.g. #623815.
 | |
|    */
 | |
|   signal_handler_id = g_signal_connect (proxy,
 | |
|                                         "g-signal",
 | |
|                                         G_CALLBACK (on_proxy_signal_received_with_name_set),
 | |
|                                         &data);
 | |
|   data.signal_received = FALSE;
 | |
|   g_dbus_proxy_call (proxy,
 | |
|                      "EmitSignalWithNameSet",
 | |
|                      NULL,  /* no arguments */
 | |
|                      G_DBUS_CALL_FLAGS_NONE,
 | |
|                      -1,
 | |
|                      NULL,  /* GCancellable */
 | |
|                      NULL,  /* GAsyncReadyCallback - we don't care about the result */
 | |
|                      NULL); /* user_data */
 | |
|   g_main_loop_run (loop);
 | |
|   g_assert (data.signal_received);
 | |
|   g_assert_cmpint (data.num_method_calls, ==, 3);
 | |
|   g_signal_handler_disconnect (proxy, signal_handler_id);
 | |
| 
 | |
|   /*
 | |
|    * Check for UNIX fd passing.
 | |
|    *
 | |
|    * The first time through, we use a very simple method call. Note that
 | |
|    * because this does not have a G_VARIANT_TYPE_HANDLE in the message body
 | |
|    * to refer to the fd, it is a GDBus-specific idiom that would not
 | |
|    * interoperate with libdbus or sd-bus
 | |
|    * (see <https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1726>).
 | |
|    *
 | |
|    * The second time, we call a method that returns a fd attached to a
 | |
|    * large message, to reproduce
 | |
|    * <https://gitlab.gnome.org/GNOME/glib/-/issues/2074>. It also happens
 | |
|    * to follow the more usual pattern for D-Bus messages containing a
 | |
|    * G_VARIANT_TYPE_HANDLE to refer to attached fds.
 | |
|    */
 | |
|   for (i = 0; i < 2; i++)
 | |
|     {
 | |
| #ifdef G_OS_UNIX
 | |
|       GDBusMessage *method_call_message;
 | |
|       GDBusMessage *method_reply_message;
 | |
|       GUnixFDList *fd_list;
 | |
|       gint fd;
 | |
|       gchar *buf;
 | |
|       gsize len;
 | |
|       gchar *buf2;
 | |
|       gsize len2;
 | |
|       const char *testfile = g_test_get_filename (G_TEST_DIST, "file.c", NULL);
 | |
|       const char *method = "OpenFile";
 | |
|       GVariant *body;
 | |
| 
 | |
|       if (i == 1)
 | |
|         method = "OpenFileWithBigMessage";
 | |
| 
 | |
|       method_call_message = g_dbus_message_new_method_call (NULL, /* name */
 | |
|                                                             "/org/gtk/GDBus/PeerTestObject",
 | |
|                                                             "org.gtk.GDBus.PeerTestInterface",
 | |
|                                                             method);
 | |
|       g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", testfile));
 | |
|       error = NULL;
 | |
|       method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
 | |
|                                                                              method_call_message,
 | |
|                                                                              G_DBUS_SEND_MESSAGE_FLAGS_NONE,
 | |
|                                                                              -1,
 | |
|                                                                              NULL, /* out_serial */
 | |
|                                                                              NULL, /* cancellable */
 | |
|                                                                              &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
 | |
| 
 | |
|       body = g_dbus_message_get_body (method_reply_message);
 | |
| 
 | |
|       if (i == 1)
 | |
|         {
 | |
|           gint32 handle = -1;
 | |
|           GVariant *junk = NULL;
 | |
| 
 | |
|           g_assert_cmpstr (g_variant_get_type_string (body), ==, "(hay)");
 | |
|           g_variant_get (body, "(h@ay)", &handle, &junk);
 | |
|           g_assert_cmpint (handle, ==, 0);
 | |
|           g_assert_cmpuint (g_variant_n_children (junk), ==, BIG_MESSAGE_ARRAY_SIZE);
 | |
|           g_variant_unref (junk);
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           g_assert_null (body);
 | |
|         }
 | |
| 
 | |
|       fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
 | |
|       g_assert (fd_list != NULL);
 | |
|       g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
 | |
|       error = NULL;
 | |
|       fd = g_unix_fd_list_get (fd_list, 0, &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_object_unref (method_call_message);
 | |
|       g_object_unref (method_reply_message);
 | |
| 
 | |
|       error = NULL;
 | |
|       len = 0;
 | |
|       buf = read_all_from_fd (fd, &len, &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_assert (buf != NULL);
 | |
|       close (fd);
 | |
| 
 | |
|       error = NULL;
 | |
|       g_file_get_contents (testfile,
 | |
|                            &buf2,
 | |
|                            &len2,
 | |
|                            &error);
 | |
|       g_assert_no_error (error);
 | |
|       g_assert_cmpmem (buf, len, buf2, len2);
 | |
|       g_free (buf2);
 | |
|       g_free (buf);
 | |
| #else
 | |
|       /* We do the same number of iterations on non-Unix, so that
 | |
|        * the method call count will match. In this case we use
 | |
|        * OpenFile both times, because the difference between this
 | |
|        * and OpenFileWithBigMessage is only relevant on Unix. */
 | |
|       error = NULL;
 | |
|       result = g_dbus_proxy_call_sync (proxy,
 | |
|                                        "OpenFile",
 | |
|                                        g_variant_new ("(s)", "boo"),
 | |
|                                        G_DBUS_CALL_FLAGS_NONE,
 | |
|                                        -1,
 | |
|                                        NULL,  /* GCancellable */
 | |
|                                        &error);
 | |
|       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
 | |
|       g_assert (result == NULL);
 | |
|       g_error_free (error);
 | |
| #endif /* G_OS_UNIX */
 | |
|     }
 | |
| 
 | |
|   /* Check that g_socket_get_credentials() work - (though this really
 | |
|    * should be in socket.c)
 | |
|    */
 | |
|   {
 | |
|     GSocket *socket;
 | |
|     GCredentials *credentials;
 | |
|     socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (g_dbus_connection_get_stream (c)));
 | |
|     g_assert (G_IS_SOCKET (socket));
 | |
|     error = NULL;
 | |
|     credentials = g_socket_get_credentials (socket, &error);
 | |
| 
 | |
| #if G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED
 | |
|     g_assert_no_error (error);
 | |
|     g_assert (G_IS_CREDENTIALS (credentials));
 | |
| 
 | |
| #ifdef G_OS_WIN32
 | |
|       {
 | |
|         DWORD *pid;
 | |
|         pid = g_credentials_get_native (credentials, G_CREDENTIALS_TYPE_WIN32_PID);
 | |
|         g_assert_cmpuint (*pid, ==, GetCurrentProcessId ());
 | |
|       }
 | |
| #else
 | |
|     g_assert_cmpuint (g_credentials_get_unix_user (credentials, NULL), ==,
 | |
|                       getuid ());
 | |
| #if G_CREDENTIALS_HAS_PID
 | |
|     g_assert_cmpint (g_credentials_get_unix_pid (credentials, &error), ==,
 | |
|                      getpid ());
 | |
|     g_assert_no_error (error);
 | |
| #else
 | |
|     g_assert_cmpint (g_credentials_get_unix_pid (credentials, &error), ==, -1);
 | |
|     g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
 | |
|     g_clear_error (&error);
 | |
| #endif /* G_CREDENTIALS_HAS_PID */
 | |
|     g_object_unref (credentials);
 | |
| #endif /* G_OS_WIN32 */
 | |
| #else
 | |
|     g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
 | |
|     g_assert (credentials == NULL);
 | |
| #endif /* G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED */
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /* bring up a connection - don't accept it - this should fail
 | |
|    */
 | |
|   data.accept_connection = FALSE;
 | |
|   error = NULL;
 | |
|   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
 | |
|                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                                NULL, /* GDBusAuthObserver */
 | |
|                                                NULL, /* cancellable */
 | |
|                                                &error);
 | |
|   _g_assert_error_domain (error, G_IO_ERROR);
 | |
|   g_error_free (error);
 | |
|   g_assert (c2 == NULL);
 | |
| 
 | |
| #if 0
 | |
|   /* TODO: THIS TEST DOESN'T WORK YET */
 | |
| 
 | |
|   /* bring up a connection - accept it.. then disconnect from the client side - check
 | |
|    * that the server side gets the disconnect signal.
 | |
|    */
 | |
|   error = NULL;
 | |
|   data.accept_connection = TRUE;
 | |
|   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
 | |
|                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                                NULL, /* GDBusAuthObserver */
 | |
|                                                NULL, /* cancellable */
 | |
|                                                &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (c2 != NULL);
 | |
|   g_assert (!g_dbus_connection_get_is_disconnected (c2));
 | |
|   while (data.num_connection_attempts < 3)
 | |
|     g_main_loop_run (loop);
 | |
|   g_assert_cmpint (data.current_connections->len, ==, 2);
 | |
|   g_assert_cmpint (data.num_connection_attempts, ==, 3);
 | |
|   g_assert (!g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
 | |
|   g_idle_add (on_do_disconnect_in_idle, c2);
 | |
|   g_debug ("==================================================");
 | |
|   g_debug ("==================================================");
 | |
|   g_debug ("==================================================");
 | |
|   g_debug ("waiting for disconnect on connection %p, stream %p",
 | |
|            data.current_connections->pdata[1],
 | |
|            g_dbus_connection_get_stream (data.current_connections->pdata[1]));
 | |
| 
 | |
|   g_timeout_add (2000, check_connection, &data);
 | |
|   //_g_assert_signal_received (G_DBUS_CONNECTION (data.current_connections->pdata[1]), "closed");
 | |
|   g_main_loop_run (loop);
 | |
|   g_assert (g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
 | |
|   g_ptr_array_set_size (data.current_connections, 1); /* remove disconnected connection object */
 | |
| #endif
 | |
| 
 | |
|   /* unref the server and stop listening for new connections
 | |
|    *
 | |
|    * This won't bring down the established connections - check that c is still connected
 | |
|    * by invoking a method
 | |
|    */
 | |
|   //g_socket_service_stop (service);
 | |
|   //g_object_unref (service);
 | |
|   g_dbus_server_stop (server);
 | |
|   g_object_unref (server);
 | |
|   server = NULL;
 | |
| 
 | |
|   error = NULL;
 | |
|   result = g_dbus_proxy_call_sync (proxy,
 | |
|                                    "HelloPeer",
 | |
|                                    g_variant_new ("(s)", "Hey Again Peer!"),
 | |
|                                    G_DBUS_CALL_FLAGS_NONE,
 | |
|                                    -1,
 | |
|                                    NULL,  /* GCancellable */
 | |
|                                    &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_variant_get (result, "(&s)", &s);
 | |
|   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
 | |
|   g_variant_unref (result);
 | |
|   g_assert_cmpint (data.num_method_calls, ==, 6);
 | |
| 
 | |
| #if 0
 | |
|   /* TODO: THIS TEST DOESN'T WORK YET */
 | |
| 
 | |
|   /* now disconnect from the server side - check that the client side gets the signal */
 | |
|   g_assert_cmpint (data.current_connections->len, ==, 1);
 | |
|   g_assert (G_DBUS_CONNECTION (data.current_connections->pdata[0]) != c);
 | |
|   g_dbus_connection_disconnect (G_DBUS_CONNECTION (data.current_connections->pdata[0]));
 | |
|   if (!g_dbus_connection_get_is_disconnected (c))
 | |
|     _g_assert_signal_received (c, "closed");
 | |
|   g_assert (g_dbus_connection_get_is_disconnected (c));
 | |
| #endif
 | |
| 
 | |
|   g_object_unref (c);
 | |
|   g_ptr_array_unref (data.current_connections);
 | |
|   g_object_unref (proxy);
 | |
| 
 | |
|   g_main_loop_quit (service_loop);
 | |
|   g_thread_join (service_thread);
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_peer (void)
 | |
| {
 | |
|   test_guid = g_dbus_generate_guid ();
 | |
|   loop = g_main_loop_new (NULL, FALSE);
 | |
| 
 | |
|   /* Run this test multiple times using different address formats to ensure
 | |
|    * they all work.
 | |
|    */
 | |
|   setup_test_address ();
 | |
|   do_test_peer ();
 | |
|   teardown_test_address ();
 | |
| 
 | |
| #ifdef G_OS_UNIX
 | |
|   setup_tmpdir_test_address ();
 | |
|   do_test_peer ();
 | |
|   teardown_test_address ();
 | |
| 
 | |
|   setup_path_test_address ();
 | |
|   do_test_peer ();
 | |
|   teardown_test_address ();
 | |
| #endif
 | |
| 
 | |
|   g_main_loop_unref (loop);
 | |
|   g_free (test_guid);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| #define VALID_GUID "0123456789abcdef0123456789abcdef"
 | |
| 
 | |
| static void
 | |
| test_peer_invalid_server (void)
 | |
| {
 | |
|   GDBusServer *server;
 | |
| 
 | |
|   if (!g_test_undefined ())
 | |
|     {
 | |
|       g_test_skip ("Not exercising programming errors");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   if (g_test_subprocess ())
 | |
|     {
 | |
|       /* This assumes we are not going to run out of GDBusServerFlags
 | |
|        * any time soon */
 | |
|       server = g_dbus_server_new_sync ("tcp:", (GDBusServerFlags) (1 << 30),
 | |
|                                        VALID_GUID,
 | |
|                                        NULL, NULL, NULL);
 | |
|       g_assert_null (server);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
 | |
|       g_test_trap_assert_failed ();
 | |
|       g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_SERVER_FLAGS_ALL*");
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_peer_invalid_conn_stream_sync (void)
 | |
| {
 | |
|   GSocket *sock;
 | |
|   GSocketConnection *socket_conn;
 | |
|   GIOStream *iostream;
 | |
|   GDBusConnection *conn;
 | |
| 
 | |
|   if (!g_test_undefined ())
 | |
|     {
 | |
|       g_test_skip ("Not exercising programming errors");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
 | |
|                        G_SOCKET_TYPE_STREAM,
 | |
|                        G_SOCKET_PROTOCOL_TCP,
 | |
|                        NULL);
 | |
| 
 | |
|   if (sock == NULL)
 | |
|     {
 | |
|       g_test_skip ("TCP not available?");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   socket_conn = g_socket_connection_factory_create_connection (sock);
 | |
|   g_assert_nonnull (socket_conn);
 | |
|   iostream = G_IO_STREAM (socket_conn);
 | |
|   g_assert_nonnull (iostream);
 | |
| 
 | |
|   if (g_test_subprocess ())
 | |
|     {
 | |
|       /* This assumes we are not going to run out of GDBusConnectionFlags
 | |
|        * any time soon */
 | |
|       conn = g_dbus_connection_new_sync (iostream, VALID_GUID,
 | |
|                                          (GDBusConnectionFlags) (1 << 30),
 | |
|                                          NULL, NULL, NULL);
 | |
|       g_assert_null (conn);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
 | |
|       g_test_trap_assert_failed ();
 | |
|       g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
 | |
|     }
 | |
| 
 | |
|   g_clear_object (&sock);
 | |
|   g_clear_object (&socket_conn);
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_peer_invalid_conn_stream_async (void)
 | |
| {
 | |
|   GSocket *sock;
 | |
|   GSocketConnection *socket_conn;
 | |
|   GIOStream *iostream;
 | |
| 
 | |
|   if (!g_test_undefined ())
 | |
|     {
 | |
|       g_test_skip ("Not exercising programming errors");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
 | |
|                        G_SOCKET_TYPE_STREAM,
 | |
|                        G_SOCKET_PROTOCOL_TCP,
 | |
|                        NULL);
 | |
| 
 | |
|   if (sock == NULL)
 | |
|     {
 | |
|       g_test_skip ("TCP not available?");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   socket_conn = g_socket_connection_factory_create_connection (sock);
 | |
|   g_assert_nonnull (socket_conn);
 | |
|   iostream = G_IO_STREAM (socket_conn);
 | |
|   g_assert_nonnull (iostream);
 | |
| 
 | |
|   if (g_test_subprocess ())
 | |
|     {
 | |
|       g_dbus_connection_new (iostream, VALID_GUID,
 | |
|                              (GDBusConnectionFlags) (1 << 30),
 | |
|                              NULL, NULL, NULL, NULL);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
 | |
|       g_test_trap_assert_failed ();
 | |
|       g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
 | |
|     }
 | |
| 
 | |
|   g_clear_object (&sock);
 | |
|   g_clear_object (&socket_conn);
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_peer_invalid_conn_addr_sync (void)
 | |
| {
 | |
|   GDBusConnection *conn;
 | |
| 
 | |
|   if (!g_test_undefined ())
 | |
|     {
 | |
|       g_test_skip ("Not exercising programming errors");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   if (g_test_subprocess ())
 | |
|     {
 | |
|       conn = g_dbus_connection_new_for_address_sync ("tcp:",
 | |
|                                                      (GDBusConnectionFlags) (1 << 30),
 | |
|                                                      NULL, NULL, NULL);
 | |
|       g_assert_null (conn);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
 | |
|       g_test_trap_assert_failed ();
 | |
|       g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_peer_invalid_conn_addr_async (void)
 | |
| {
 | |
|   if (!g_test_undefined ())
 | |
|     {
 | |
|       g_test_skip ("Not exercising programming errors");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   if (g_test_subprocess ())
 | |
|     {
 | |
|       g_dbus_connection_new_for_address ("tcp:",
 | |
|                                          (GDBusConnectionFlags) (1 << 30),
 | |
|                                          NULL, NULL, NULL, NULL);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
 | |
|       g_test_trap_assert_failed ();
 | |
|       g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static void
 | |
| test_peer_signals (void)
 | |
| {
 | |
|   GDBusConnection *c;
 | |
|   GDBusProxy *proxy;
 | |
|   GError *error = NULL;
 | |
|   PeerData data;
 | |
|   GThread *service_thread;
 | |
| 
 | |
|   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1620");
 | |
| 
 | |
|   test_guid = g_dbus_generate_guid ();
 | |
|   loop = g_main_loop_new (NULL, FALSE);
 | |
| 
 | |
|   setup_test_address ();
 | |
|   memset (&data, '\0', sizeof (PeerData));
 | |
|   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
 | |
| 
 | |
|   /* bring up a server - we run the server in a different thread to avoid deadlocks */
 | |
|   service_thread = g_thread_new ("test_peer",
 | |
|                                  service_thread_func,
 | |
|                                  &data);
 | |
|   await_service_loop ();
 | |
|   g_assert_nonnull (server);
 | |
| 
 | |
|   /* bring up a connection and accept it */
 | |
|   data.accept_connection = TRUE;
 | |
|   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
 | |
|                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                               NULL, /* GDBusAuthObserver */
 | |
|                                               NULL, /* cancellable */
 | |
|                                               &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert_nonnull (c);
 | |
|   while (data.current_connections->len < 1)
 | |
|     g_main_loop_run (loop);
 | |
|   g_assert_cmpint (data.current_connections->len, ==, 1);
 | |
|   g_assert_cmpint (data.num_connection_attempts, ==, 1);
 | |
|   g_assert_null (g_dbus_connection_get_unique_name (c));
 | |
|   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
 | |
| 
 | |
|   /* Check that we can create a proxy with a non-NULL bus name, even though it's
 | |
|    * irrelevant in the non-message-bus case. Since the server runs in another
 | |
|    * thread it's fine to use synchronous blocking API here.
 | |
|    */
 | |
|   proxy = g_dbus_proxy_new_sync (c,
 | |
|                                  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
 | |
|                                  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
 | |
|                                  NULL,
 | |
|                                  ":1.1", /* bus_name */
 | |
|                                  "/org/gtk/GDBus/PeerTestObject",
 | |
|                                  "org.gtk.GDBus.PeerTestInterface",
 | |
|                                  NULL, /* GCancellable */
 | |
|                                  &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert_nonnull (proxy);
 | |
| 
 | |
|   /* unref the server and stop listening for new connections */
 | |
|   g_dbus_server_stop (server);
 | |
|   g_clear_object (&server);
 | |
| 
 | |
|   g_object_unref (c);
 | |
|   g_ptr_array_unref (data.current_connections);
 | |
|   g_object_unref (proxy);
 | |
| 
 | |
|   g_main_loop_quit (service_loop);
 | |
|   g_thread_join (service_thread);
 | |
| 
 | |
|   teardown_test_address ();
 | |
| 
 | |
|   g_main_loop_unref (loop);
 | |
|   g_free (test_guid);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| 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_free_full (data->connections, g_object_unref);
 | |
|   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 */
 | |
|   { 0 }
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
 | |
| static gboolean
 | |
| 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).
 | |
|    */
 | |
|   g_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);
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| 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 (tmp_address,
 | |
|                                          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_dbus_server_stop (data->server);
 | |
|   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;
 | |
| 
 | |
|   test_guid = g_dbus_generate_guid ();
 | |
|   loop = g_main_loop_new (NULL, FALSE);
 | |
| 
 | |
|   setup_test_address ();
 | |
| 
 | |
|   data = g_new0 (DmpData, 1);
 | |
| 
 | |
|   service_thread = g_thread_new ("dmp",
 | |
|                                  dmp_thread_func,
 | |
|                                  data);
 | |
|   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);
 | |
|   teardown_test_address ();
 | |
| 
 | |
|   g_main_loop_unref (loop);
 | |
|   g_free (test_guid);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static gboolean
 | |
| nonce_tcp_on_authorize_authenticated_peer (GDBusAuthObserver *observer,
 | |
|                                            GIOStream         *stream,
 | |
|                                            GCredentials      *credentials,
 | |
|                                            gpointer           user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
|   gboolean authorized;
 | |
| 
 | |
|   data->num_connection_attempts++;
 | |
| 
 | |
|   authorized = TRUE;
 | |
|   if (!data->accept_connection)
 | |
|     {
 | |
|       authorized = FALSE;
 | |
|       g_main_loop_quit (loop);
 | |
|     }
 | |
| 
 | |
|   return authorized;
 | |
| }
 | |
| 
 | |
| /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
 | |
| static gboolean
 | |
| nonce_tcp_on_new_connection (GDBusServer *server,
 | |
|                              GDBusConnection *connection,
 | |
|                              gpointer user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
| 
 | |
|   g_ptr_array_add (data->current_connections, g_object_ref (connection));
 | |
| 
 | |
|   g_main_loop_quit (loop);
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static gpointer
 | |
| nonce_tcp_service_thread_func (gpointer user_data)
 | |
| {
 | |
|   PeerData *data = user_data;
 | |
|   GMainContext *service_context;
 | |
|   GDBusAuthObserver *observer;
 | |
|   GError *error;
 | |
| 
 | |
|   service_context = g_main_context_new ();
 | |
|   g_main_context_push_thread_default (service_context);
 | |
| 
 | |
|   error = NULL;
 | |
|   observer = g_dbus_auth_observer_new ();
 | |
|   server = g_dbus_server_new_sync ("nonce-tcp:host=127.0.0.1",
 | |
|                                    G_DBUS_SERVER_FLAGS_NONE,
 | |
|                                    test_guid,
 | |
|                                    observer,
 | |
|                                    NULL, /* cancellable */
 | |
|                                    &error);
 | |
|   g_assert_no_error (error);
 | |
| 
 | |
|   g_signal_connect (server,
 | |
|                     "new-connection",
 | |
|                     G_CALLBACK (nonce_tcp_on_new_connection),
 | |
|                     data);
 | |
|   g_signal_connect (observer,
 | |
|                     "authorize-authenticated-peer",
 | |
|                     G_CALLBACK (nonce_tcp_on_authorize_authenticated_peer),
 | |
|                     data);
 | |
|   g_object_unref (observer);
 | |
| 
 | |
|   g_dbus_server_start (server);
 | |
| 
 | |
|   run_service_loop (service_context);
 | |
| 
 | |
|   g_main_context_pop_thread_default (service_context);
 | |
| 
 | |
|   teardown_service_loop ();
 | |
|   g_main_context_unref (service_context);
 | |
| 
 | |
|   /* test code specifically unrefs the server - see below */
 | |
|   g_assert (server == NULL);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_nonce_tcp (void)
 | |
| {
 | |
|   PeerData data;
 | |
|   GError *error;
 | |
|   GThread *service_thread;
 | |
|   GDBusConnection *c;
 | |
|   gchar *s;
 | |
|   gchar *nonce_file;
 | |
|   gboolean res;
 | |
|   const gchar *address;
 | |
|   int fd;
 | |
| 
 | |
|   test_guid = g_dbus_generate_guid ();
 | |
|   loop = g_main_loop_new (NULL, FALSE);
 | |
| 
 | |
|   memset (&data, '\0', sizeof (PeerData));
 | |
|   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
 | |
| 
 | |
|   error = NULL;
 | |
|   server = NULL;
 | |
|   service_thread = g_thread_new ("nonce-tcp-service",
 | |
|                                  nonce_tcp_service_thread_func,
 | |
|                                  &data);
 | |
|   await_service_loop ();
 | |
|   g_assert (server != NULL);
 | |
| 
 | |
|   /* bring up a connection and accept it */
 | |
|   data.accept_connection = TRUE;
 | |
|   error = NULL;
 | |
|   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
 | |
|                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                               NULL, /* GDBusAuthObserver */
 | |
|                                               NULL, /* cancellable */
 | |
|                                               &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (c != NULL);
 | |
|   while (data.current_connections->len < 1)
 | |
|     g_thread_yield ();
 | |
|   g_assert_cmpint (data.current_connections->len, ==, 1);
 | |
|   g_assert_cmpint (data.num_connection_attempts, ==, 1);
 | |
|   g_assert (g_dbus_connection_get_unique_name (c) == NULL);
 | |
|   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
 | |
|   g_object_unref (c);
 | |
| 
 | |
|   /* now, try to subvert the nonce file (this assumes noncefile is the last key/value pair)
 | |
|    */
 | |
| 
 | |
|   address = g_dbus_server_get_client_address (server);
 | |
| 
 | |
|   s = strstr (address, "noncefile=");
 | |
|   g_assert (s != NULL);
 | |
|   s += sizeof "noncefile=" - 1;
 | |
|   nonce_file = g_uri_unescape_string (s, NULL); /* URI-unescaping should be good enough */
 | |
| 
 | |
|   /* First try invalid data in the nonce file - this will actually
 | |
|    * make the client send this and the server will reject it. The way
 | |
|    * it works is that if the nonce doesn't match, the server will
 | |
|    * simply close the connection. So, from the client point of view,
 | |
|    * we can see a variety of errors.
 | |
|    */
 | |
|   error = NULL;
 | |
|   res = g_file_set_contents (nonce_file,
 | |
|                              "0123456789012345",
 | |
|                              -1,
 | |
|                              &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (res);
 | |
|   c = g_dbus_connection_new_for_address_sync (address,
 | |
|                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                               NULL, /* GDBusAuthObserver */
 | |
|                                               NULL, /* cancellable */
 | |
|                                               &error);
 | |
|   _g_assert_error_domain (error, G_IO_ERROR);
 | |
|   g_error_free (error);
 | |
|   g_assert (c == NULL);
 | |
| 
 | |
|   /* Then try with a nonce-file of incorrect length - this will make
 | |
|    * the client complain - we won't even try connecting to the server
 | |
|    * for this
 | |
|    */
 | |
|   error = NULL;
 | |
|   res = g_file_set_contents (nonce_file,
 | |
|                              "0123456789012345_",
 | |
|                              -1,
 | |
|                              &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (res);
 | |
|   c = g_dbus_connection_new_for_address_sync (address,
 | |
|                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                               NULL, /* GDBusAuthObserver */
 | |
|                                               NULL, /* cancellable */
 | |
|                                               &error);
 | |
|   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
 | |
|   g_error_free (error);
 | |
|   g_assert (c == NULL);
 | |
| 
 | |
|   /* Finally try with no nonce-file at all */
 | |
|   g_assert_cmpint (g_unlink (nonce_file), ==, 0);
 | |
|   error = NULL;
 | |
|   c = g_dbus_connection_new_for_address_sync (address,
 | |
|                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                               NULL, /* GDBusAuthObserver */
 | |
|                                               NULL, /* cancellable */
 | |
|                                               &error);
 | |
|   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
 | |
|   g_error_free (error);
 | |
|   g_assert (c == NULL);
 | |
| 
 | |
|   /* Recreate the nonce-file so we can ensure the server deletes it when stopped. */
 | |
|   fd = g_creat (nonce_file, 0600);
 | |
|   g_assert_cmpint (fd, !=, -1);
 | |
|   g_close (fd, NULL);
 | |
| 
 | |
|   g_dbus_server_stop (server);
 | |
|   g_object_unref (server);
 | |
|   server = NULL;
 | |
| 
 | |
|   g_assert_false (g_file_test (nonce_file, G_FILE_TEST_EXISTS));
 | |
|   g_free (nonce_file);
 | |
| 
 | |
|   g_main_loop_quit (service_loop);
 | |
|   g_thread_join (service_thread);
 | |
| 
 | |
|   g_ptr_array_unref (data.current_connections);
 | |
| 
 | |
|   g_main_loop_unref (loop);
 | |
|   g_free (test_guid);
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_credentials (void)
 | |
| {
 | |
|   GCredentials *c1, *c2;
 | |
|   GError *error;
 | |
|   gchar *desc;
 | |
|   gboolean same;
 | |
| 
 | |
|   c1 = g_credentials_new ();
 | |
|   c2 = g_credentials_new ();
 | |
| 
 | |
|   error = NULL;
 | |
| #ifdef G_OS_UNIX
 | |
|   if (g_credentials_set_unix_user (c2, getuid (), &error))
 | |
|     g_assert_no_error (error);
 | |
| #endif
 | |
| 
 | |
|   same = g_credentials_is_same_user (c1, c2, &error);
 | |
| #ifdef G_OS_UNIX
 | |
|   g_assert (same);
 | |
|   g_assert_no_error (error);
 | |
| #else
 | |
|   g_assert (!same);
 | |
|   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
 | |
|   g_clear_error (&error);
 | |
| #endif
 | |
| 
 | |
|   desc = g_credentials_to_string (c1);
 | |
|   g_assert (desc != NULL);
 | |
|   g_free (desc);
 | |
| 
 | |
|   g_object_unref (c1);
 | |
|   g_object_unref (c2);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static gboolean
 | |
| tcp_anonymous_on_new_connection (GDBusServer     *server,
 | |
|                                  GDBusConnection *connection,
 | |
|                                  gpointer         user_data)
 | |
| {
 | |
|   gboolean *seen_connection = user_data;
 | |
|   *seen_connection = TRUE;
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static gpointer
 | |
| tcp_anonymous_service_thread_func (gpointer user_data)
 | |
| {
 | |
|   gboolean *seen_connection = user_data;
 | |
|   GMainContext *service_context;
 | |
|   GError *error;
 | |
| 
 | |
|   service_context = g_main_context_new ();
 | |
|   g_main_context_push_thread_default (service_context);
 | |
| 
 | |
|   error = NULL;
 | |
|   server = g_dbus_server_new_sync ("tcp:host=127.0.0.1",
 | |
|                                    G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS,
 | |
|                                    test_guid,
 | |
|                                    NULL, /* GDBusObserver* */
 | |
|                                    NULL, /* GCancellable* */
 | |
|                                    &error);
 | |
|   g_assert_no_error (error);
 | |
| 
 | |
|   g_signal_connect (server,
 | |
|                     "new-connection",
 | |
|                     G_CALLBACK (tcp_anonymous_on_new_connection),
 | |
|                     seen_connection);
 | |
| 
 | |
|   g_dbus_server_start (server);
 | |
| 
 | |
|   run_service_loop (service_context);
 | |
| 
 | |
|   g_main_context_pop_thread_default (service_context);
 | |
| 
 | |
|   teardown_service_loop ();
 | |
|   g_main_context_unref (service_context);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| test_tcp_anonymous (void)
 | |
| {
 | |
|   gboolean seen_connection;
 | |
|   GThread *service_thread;
 | |
|   GDBusConnection *connection;
 | |
|   GError *error;
 | |
| 
 | |
|   test_guid = g_dbus_generate_guid ();
 | |
|   loop = g_main_loop_new (NULL, FALSE);
 | |
| 
 | |
|   seen_connection = FALSE;
 | |
|   service_thread = g_thread_new ("tcp-anon-service",
 | |
|                                  tcp_anonymous_service_thread_func,
 | |
|                                  &seen_connection);
 | |
|   await_service_loop ();
 | |
|   g_assert (server != NULL);
 | |
| 
 | |
|   error = NULL;
 | |
|   connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
 | |
|                                                        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                                        NULL, /* GDBusAuthObserver* */
 | |
|                                                        NULL, /* GCancellable */
 | |
|                                                        &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (connection != NULL);
 | |
| 
 | |
|   while (!seen_connection)
 | |
|     g_thread_yield ();
 | |
| 
 | |
|   g_object_unref (connection);
 | |
| 
 | |
|   g_main_loop_quit (service_loop);
 | |
|   g_dbus_server_stop (server);
 | |
|   g_object_unref (server);
 | |
|   server = NULL;
 | |
| 
 | |
|   g_thread_join (service_thread);
 | |
| 
 | |
|   g_main_loop_unref (loop);
 | |
|   g_free (test_guid);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| static GDBusServer *codegen_server = NULL;
 | |
| 
 | |
| static gboolean
 | |
| codegen_on_animal_poke (ExampleAnimal          *animal,
 | |
|                         GDBusMethodInvocation  *invocation,
 | |
|                         gboolean                make_sad,
 | |
|                         gboolean                make_happy,
 | |
|                         gpointer                user_data)
 | |
| {
 | |
|   if ((make_sad && make_happy) || (!make_sad && !make_happy))
 | |
|     {
 | |
|       g_main_loop_quit (service_loop);
 | |
| 
 | |
|       g_dbus_method_invocation_return_dbus_error (invocation,
 | |
|                                                   "org.gtk.GDBus.Examples.ObjectManager.Error.Failed",
 | |
|                                                   "Exactly one of make_sad or make_happy must be TRUE");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   if (make_sad)
 | |
|     {
 | |
|       if (g_strcmp0 (example_animal_get_mood (animal), "Sad") == 0)
 | |
|         {
 | |
|           g_dbus_method_invocation_return_dbus_error (invocation,
 | |
|                                                       "org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad",
 | |
|                                                       "Sad animal is already sad");
 | |
|           goto out;
 | |
|         }
 | |
| 
 | |
|       example_animal_set_mood (animal, "Sad");
 | |
|       example_animal_complete_poke (animal, invocation);
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   if (make_happy)
 | |
|     {
 | |
|       if (g_strcmp0 (example_animal_get_mood (animal), "Happy") == 0)
 | |
|         {
 | |
|           g_dbus_method_invocation_return_dbus_error (invocation,
 | |
|                                                       "org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy",
 | |
|                                                       "Happy animal is already happy");
 | |
|           goto out;
 | |
|         }
 | |
| 
 | |
|       example_animal_set_mood (animal, "Happy");
 | |
|       example_animal_complete_poke (animal, invocation);
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   g_assert_not_reached ();
 | |
| 
 | |
|  out:
 | |
|   return G_DBUS_METHOD_INVOCATION_HANDLED;
 | |
| }
 | |
| 
 | |
| /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
 | |
| static gboolean
 | |
| codegen_on_new_connection (GDBusServer *server,
 | |
|                            GDBusConnection *connection,
 | |
|                            gpointer user_data)
 | |
| {
 | |
|   ExampleAnimal *animal = user_data;
 | |
|   GError        *error = NULL;
 | |
| 
 | |
|   /* g_printerr ("Client connected.\n" */
 | |
|   /*          "Negotiated capabilities: unix-fd-passing=%d\n", */
 | |
|   /*          g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); */
 | |
| 
 | |
|   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (animal), connection,
 | |
|                                     "/Example/Animals/000", &error);
 | |
|   g_assert_no_error (error);
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static gpointer
 | |
| codegen_service_thread_func (gpointer user_data)
 | |
| {
 | |
|   GMainContext   *service_context;
 | |
|   ExampleAnimal  *animal;
 | |
|   GError         *error = NULL;
 | |
| 
 | |
|   service_context = g_main_context_new ();
 | |
|   g_main_context_push_thread_default (service_context);
 | |
| 
 | |
|   /* Create the animal in the right thread context */
 | |
|   animal = example_animal_skeleton_new ();
 | |
| 
 | |
|   /* Handle Poke() D-Bus method invocations on the .Animal interface */
 | |
|   g_signal_connect (animal, "handle-poke",
 | |
|                     G_CALLBACK (codegen_on_animal_poke),
 | |
|                     NULL); /* user_data */
 | |
| 
 | |
|   codegen_server = g_dbus_server_new_sync (tmp_address,
 | |
|                                            G_DBUS_SERVER_FLAGS_NONE,
 | |
|                                            test_guid,
 | |
|                                            NULL, /* observer */
 | |
|                                            NULL, /* cancellable */
 | |
|                                            &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_dbus_server_start (codegen_server);
 | |
| 
 | |
|   g_signal_connect (codegen_server, "new-connection",
 | |
|                     G_CALLBACK (codegen_on_new_connection),
 | |
|                     animal);
 | |
| 
 | |
|   run_service_loop (service_context);
 | |
| 
 | |
|   g_object_unref (animal);
 | |
| 
 | |
|   g_main_context_pop_thread_default (service_context);
 | |
| 
 | |
|   teardown_service_loop ();
 | |
|   g_main_context_unref (service_context);
 | |
| 
 | |
|   g_dbus_server_stop (codegen_server);
 | |
|   g_object_unref (codegen_server);
 | |
|   codegen_server = NULL;
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| static gboolean
 | |
| codegen_quit_mainloop_timeout (gpointer data)
 | |
| {
 | |
|   g_main_loop_quit (loop);
 | |
|   return G_SOURCE_REMOVE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| codegen_test_peer (void)
 | |
| {
 | |
|   GDBusConnection     *connection;
 | |
|   ExampleAnimal       *animal1, *animal2;
 | |
|   GThread             *service_thread;
 | |
|   GError              *error = NULL;
 | |
|   GVariant            *value;
 | |
|   const gchar         *s;
 | |
| 
 | |
|   test_guid = g_dbus_generate_guid ();
 | |
|   loop = g_main_loop_new (NULL, FALSE);
 | |
| 
 | |
|   setup_test_address ();
 | |
| 
 | |
|   /* bring up a server - we run the server in a different thread to avoid deadlocks */
 | |
|   service_thread = g_thread_new ("codegen_test_peer",
 | |
|                                  codegen_service_thread_func,
 | |
|                                  NULL);
 | |
|   await_service_loop ();
 | |
|   g_assert (codegen_server != NULL);
 | |
| 
 | |
|   /* Get an animal 1 ...  */
 | |
|   connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
 | |
|                                                        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                                        NULL, /* GDBusAuthObserver */
 | |
|                                                        NULL, /* cancellable */
 | |
|                                                        &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (connection != NULL);
 | |
| 
 | |
|   animal1 = example_animal_proxy_new_sync (connection, 0, NULL,
 | |
|                                            "/Example/Animals/000", NULL, &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (animal1 != NULL);
 | |
|   g_object_unref (connection);
 | |
| 
 | |
|   /* Get animal 2 ...  */
 | |
|   connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
 | |
|                                                        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
 | |
|                                                        NULL, /* GDBusAuthObserver */
 | |
|                                                        NULL, /* cancellable */
 | |
|                                                        &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (connection != NULL);
 | |
| 
 | |
|   animal2 = example_animal_proxy_new_sync (connection, 0, NULL,
 | |
|                                            "/Example/Animals/000", NULL, &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (animal2 != NULL);
 | |
|   g_object_unref (connection);
 | |
| 
 | |
|   /* Make animal sad via animal1  */
 | |
|   example_animal_call_poke_sync (animal1, TRUE, FALSE, NULL, &error);
 | |
|   g_assert_no_error (error);
 | |
| 
 | |
|   /* Poke server and make sure animal is updated */
 | |
|   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal1),
 | |
|                                   DBUS_INTERFACE_PEER ".Ping",
 | |
|                                   NULL, G_DBUS_CALL_FLAGS_NONE, -1,
 | |
|                                   NULL, &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (value != NULL);
 | |
|   g_variant_unref (value);
 | |
| 
 | |
|   /* Give the proxies a chance to refresh in the default main loop */
 | |
|   g_timeout_add (100, codegen_quit_mainloop_timeout, NULL);
 | |
|   g_main_loop_run (loop);
 | |
| 
 | |
|   /* Assert animals are sad */
 | |
|   g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Sad");
 | |
|   g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Sad");
 | |
| 
 | |
|   /* Make animal happy via animal2  */
 | |
|   example_animal_call_poke_sync (animal2, FALSE, TRUE, NULL, &error);
 | |
|   g_assert_no_error (error);
 | |
| 
 | |
|   /* Some random unrelated call, just to get some test coverage */
 | |
|   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal2),
 | |
|                                   DBUS_INTERFACE_PEER ".GetMachineId",
 | |
|                                   NULL, G_DBUS_CALL_FLAGS_NONE, -1,
 | |
|                                   NULL, &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_variant_get (value, "(&s)", &s);
 | |
|   g_test_message ("Machine ID: %s", s);
 | |
|   /* It's valid for machine-id inside containers to be empty, so we
 | |
|    * need to test for that possibility
 | |
|    */
 | |
|   g_assert ((s == NULL || *s == '\0') || g_dbus_is_guid (s));
 | |
|   g_variant_unref (value);
 | |
|   
 | |
|   /* Poke server and make sure animal is updated */
 | |
|   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal2),
 | |
|                                   DBUS_INTERFACE_PEER ".Ping",
 | |
|                                   NULL, G_DBUS_CALL_FLAGS_NONE, -1,
 | |
|                                   NULL, &error);
 | |
|   g_assert_no_error (error);
 | |
|   g_assert (value != NULL);
 | |
|   g_variant_unref (value);
 | |
| 
 | |
|   /* Give the proxies a chance to refresh in the default main loop */
 | |
|   g_timeout_add (1000, codegen_quit_mainloop_timeout, NULL);
 | |
|   g_main_loop_run (loop);
 | |
| 
 | |
|   /* Assert animals are happy */
 | |
|   g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Happy");
 | |
|   g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Happy");
 | |
| 
 | |
|   /* This final call making the animal happy and sad will cause
 | |
|    * the server to quit, when the server quits we dont get property
 | |
|    * change notifications anyway because those are done from an idle handler
 | |
|    */
 | |
|   example_animal_call_poke_sync (animal2, TRUE, TRUE, NULL, &error);
 | |
|   g_clear_error (&error);
 | |
| 
 | |
|   g_object_unref (animal1);
 | |
|   g_object_unref (animal2);
 | |
|   g_thread_join (service_thread);
 | |
| 
 | |
|   teardown_test_address ();
 | |
| 
 | |
|   g_main_loop_unref (loop);
 | |
|   g_free (test_guid);
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------------------------------------- */
 | |
| 
 | |
| 
 | |
| int
 | |
| main (int   argc,
 | |
|       char *argv[])
 | |
| {
 | |
|   gint ret;
 | |
|   GDBusNodeInfo *introspection_data = NULL;
 | |
| 
 | |
|   g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
 | |
| 
 | |
|   introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
 | |
|   g_assert (introspection_data != NULL);
 | |
|   test_interface_introspection_data = introspection_data->interfaces[0];
 | |
| 
 | |
|   g_test_add_func ("/gdbus/peer-to-peer", test_peer);
 | |
|   g_test_add_func ("/gdbus/peer-to-peer/invalid/server",
 | |
|                    test_peer_invalid_server);
 | |
|   g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/stream/async",
 | |
|                    test_peer_invalid_conn_stream_async);
 | |
|   g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/stream/sync",
 | |
|                    test_peer_invalid_conn_stream_sync);
 | |
|   g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/addr/async",
 | |
|                    test_peer_invalid_conn_addr_async);
 | |
|   g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/addr/sync",
 | |
|                    test_peer_invalid_conn_addr_sync);
 | |
|   g_test_add_func ("/gdbus/peer-to-peer/signals", test_peer_signals);
 | |
|   g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing);
 | |
|   g_test_add_func ("/gdbus/nonce-tcp", test_nonce_tcp);
 | |
| 
 | |
|   g_test_add_func ("/gdbus/tcp-anonymous", test_tcp_anonymous);
 | |
|   g_test_add_func ("/gdbus/credentials", test_credentials);
 | |
|   g_test_add_func ("/gdbus/codegen-peer-to-peer", codegen_test_peer);
 | |
| 
 | |
|   ret = g_test_run ();
 | |
| 
 | |
|   g_dbus_node_info_unref (introspection_data);
 | |
| 
 | |
|   return ret;
 | |
| }
 |