• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
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.1 of the License, or (at your option) any later version.
9  *
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.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20 
21 #include "config.h"
22 
23 #include <gio/gio.h>
24 #include <unistd.h>
25 #include <string.h>
26 
27 /* for open(2) */
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <string.h>
32 
33 /* for g_unlink() */
34 #include <glib/gstdio.h>
35 
36 #include <gio/gnetworking.h>
37 #include <gio/gunixsocketaddress.h>
38 #include <gio/gunixfdlist.h>
39 #include <gio/gcredentialsprivate.h>
40 
41 #ifdef G_OS_UNIX
42 #include <gio/gunixconnection.h>
43 #include <errno.h>
44 #endif
45 
46 #include "gdbus-tests.h"
47 
48 #include "gdbus-object-manager-example/objectmanager-gen.h"
49 
50 #ifdef G_OS_UNIX
51 static gboolean is_unix = TRUE;
52 #else
53 static gboolean is_unix = FALSE;
54 #endif
55 
56 static gchar *tmpdir = NULL;
57 static gchar *tmp_address = NULL;
58 static gchar *test_guid = NULL;
59 static GMutex service_loop_lock;
60 static GCond service_loop_cond;
61 static GMainLoop *service_loop = NULL;
62 static GDBusServer *server = NULL;
63 static GMainLoop *loop = NULL;
64 
65 /* ---------------------------------------------------------------------------------------------------- */
66 /* Test that peer-to-peer connections work */
67 /* ---------------------------------------------------------------------------------------------------- */
68 
69 
70 typedef struct
71 {
72   gboolean accept_connection;
73   gint num_connection_attempts;
74   GPtrArray *current_connections;
75   guint num_method_calls;
76   gboolean signal_received;
77 } PeerData;
78 
79 static const gchar *test_interface_introspection_xml =
80   "<node>"
81   "  <interface name='org.gtk.GDBus.PeerTestInterface'>"
82   "    <method name='HelloPeer'>"
83   "      <arg type='s' name='greeting' direction='in'/>"
84   "      <arg type='s' name='response' direction='out'/>"
85   "    </method>"
86   "    <method name='EmitSignal'/>"
87   "    <method name='EmitSignalWithNameSet'/>"
88   "    <method name='OpenFile'>"
89   "      <arg type='s' name='path' direction='in'/>"
90   "    </method>"
91   "    <signal name='PeerSignal'>"
92   "      <arg type='s' name='a_string'/>"
93   "    </signal>"
94   "    <property type='s' name='PeerProperty' access='read'/>"
95   "  </interface>"
96   "</node>";
97 static GDBusInterfaceInfo *test_interface_introspection_data = NULL;
98 
99 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)100 test_interface_method_call (GDBusConnection       *connection,
101                             const gchar           *sender,
102                             const gchar           *object_path,
103                             const gchar           *interface_name,
104                             const gchar           *method_name,
105                             GVariant              *parameters,
106                             GDBusMethodInvocation *invocation,
107                             gpointer               user_data)
108 {
109   PeerData *data = user_data;
110   const GDBusMethodInfo *info;
111 
112   data->num_method_calls++;
113 
114   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
115   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
116 
117   info = g_dbus_method_invocation_get_method_info (invocation);
118   g_assert_cmpstr (info->name, ==, method_name);
119 
120   if (g_strcmp0 (method_name, "HelloPeer") == 0)
121     {
122       const gchar *greeting;
123       gchar *response;
124 
125       g_variant_get (parameters, "(&s)", &greeting);
126 
127       response = g_strdup_printf ("You greeted me with '%s'.",
128                                   greeting);
129       g_dbus_method_invocation_return_value (invocation,
130                                              g_variant_new ("(s)", response));
131       g_free (response);
132     }
133   else if (g_strcmp0 (method_name, "EmitSignal") == 0)
134     {
135       GError *error;
136 
137       error = NULL;
138       g_dbus_connection_emit_signal (connection,
139                                      NULL,
140                                      "/org/gtk/GDBus/PeerTestObject",
141                                      "org.gtk.GDBus.PeerTestInterface",
142                                      "PeerSignal",
143                                      NULL,
144                                      &error);
145       g_assert_no_error (error);
146       g_dbus_method_invocation_return_value (invocation, NULL);
147     }
148   else if (g_strcmp0 (method_name, "EmitSignalWithNameSet") == 0)
149     {
150       GError *error;
151       gboolean ret;
152       GDBusMessage *message;
153 
154       message = g_dbus_message_new_signal ("/org/gtk/GDBus/PeerTestObject",
155                                            "org.gtk.GDBus.PeerTestInterface",
156                                            "PeerSignalWithNameSet");
157       g_dbus_message_set_sender (message, ":1.42");
158 
159       error = NULL;
160       ret = g_dbus_connection_send_message (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error);
161       g_assert_no_error (error);
162       g_assert (ret);
163       g_object_unref (message);
164 
165       g_dbus_method_invocation_return_value (invocation, NULL);
166     }
167   else if (g_strcmp0 (method_name, "OpenFile") == 0)
168     {
169 #ifdef G_OS_UNIX
170       const gchar *path;
171       GDBusMessage *reply;
172       GError *error;
173       gint fd;
174       GUnixFDList *fd_list;
175 
176       g_variant_get (parameters, "(&s)", &path);
177 
178       fd_list = g_unix_fd_list_new ();
179 
180       error = NULL;
181 
182       fd = g_open (path, O_RDONLY, 0);
183       g_assert (fd != -1);
184       g_unix_fd_list_append (fd_list, fd, &error);
185       g_assert_no_error (error);
186       close (fd);
187 
188       reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
189       g_dbus_message_set_unix_fd_list (reply, fd_list);
190       g_object_unref (fd_list);
191       g_object_unref (invocation);
192 
193       error = NULL;
194       g_dbus_connection_send_message (connection,
195                                       reply,
196                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
197                                       NULL, /* out_serial */
198                                       &error);
199       g_assert_no_error (error);
200       g_object_unref (reply);
201 #else
202       g_dbus_method_invocation_return_dbus_error (invocation,
203                                                   "org.gtk.GDBus.NotOnUnix",
204                                                   "Your OS does not support file descriptor passing");
205 #endif
206     }
207   else
208     {
209       g_assert_not_reached ();
210     }
211 }
212 
213 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)214 test_interface_get_property (GDBusConnection  *connection,
215                              const gchar      *sender,
216                              const gchar      *object_path,
217                              const gchar      *interface_name,
218                              const gchar      *property_name,
219                              GError          **error,
220                              gpointer          user_data)
221 {
222   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
223   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
224   g_assert_cmpstr (property_name, ==, "PeerProperty");
225 
226   return g_variant_new_string ("ThePropertyValue");
227 }
228 
229 
230 static const GDBusInterfaceVTable test_interface_vtable =
231 {
232   test_interface_method_call,
233   test_interface_get_property,
234   NULL  /* set_property */
235 };
236 
237 static void
on_proxy_signal_received(GDBusProxy * proxy,gchar * sender_name,gchar * signal_name,GVariant * parameters,gpointer user_data)238 on_proxy_signal_received (GDBusProxy *proxy,
239                           gchar      *sender_name,
240                           gchar      *signal_name,
241                           GVariant   *parameters,
242                           gpointer    user_data)
243 {
244   PeerData *data = user_data;
245 
246   data->signal_received = TRUE;
247 
248   g_assert (sender_name == NULL);
249   g_assert_cmpstr (signal_name, ==, "PeerSignal");
250   g_main_loop_quit (loop);
251 }
252 
253 static void
on_proxy_signal_received_with_name_set(GDBusProxy * proxy,gchar * sender_name,gchar * signal_name,GVariant * parameters,gpointer user_data)254 on_proxy_signal_received_with_name_set (GDBusProxy *proxy,
255                                         gchar      *sender_name,
256                                         gchar      *signal_name,
257                                         GVariant   *parameters,
258                                         gpointer    user_data)
259 {
260   PeerData *data = user_data;
261 
262   data->signal_received = TRUE;
263 
264   g_assert_cmpstr (sender_name, ==, ":1.42");
265   g_assert_cmpstr (signal_name, ==, "PeerSignalWithNameSet");
266   g_main_loop_quit (loop);
267 }
268 
269 /* ---------------------------------------------------------------------------------------------------- */
270 
271 static void
setup_test_address(void)272 setup_test_address (void)
273 {
274   if (is_unix)
275     {
276       g_test_message ("Testing with unix:dir address");
277       tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
278       tmp_address = g_strdup_printf ("unix:dir=%s", tmpdir);
279     }
280   else
281     tmp_address = g_strdup ("nonce-tcp:host=127.0.0.1");
282 }
283 
284 #ifdef G_OS_UNIX
285 static void
setup_tmpdir_test_address(void)286 setup_tmpdir_test_address (void)
287 {
288   g_test_message ("Testing with unix:tmpdir address");
289   tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
290   tmp_address = g_strdup_printf ("unix:tmpdir=%s", tmpdir);
291 }
292 
293 static void
setup_path_test_address(void)294 setup_path_test_address (void)
295 {
296   g_test_message ("Testing with unix:path address");
297   tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
298   tmp_address = g_strdup_printf ("unix:path=%s/gdbus-peer-socket", tmpdir);
299 }
300 #endif
301 
302 static void
teardown_test_address(void)303 teardown_test_address (void)
304 {
305   g_free (tmp_address);
306   if (tmpdir)
307     {
308       /* Ensuring the rmdir succeeds also ensures any sockets created on the
309        * filesystem are also deleted.
310        */
311       g_assert_cmpstr (g_rmdir (tmpdir) == 0 ? "OK" : g_strerror (errno),
312                        ==, "OK");
313       g_clear_pointer (&tmpdir, g_free);
314     }
315 }
316 
317 /* ---------------------------------------------------------------------------------------------------- */
318 
319 static gboolean
on_authorize_authenticated_peer(GDBusAuthObserver * observer,GIOStream * stream,GCredentials * credentials,gpointer user_data)320 on_authorize_authenticated_peer (GDBusAuthObserver *observer,
321                                  GIOStream         *stream,
322                                  GCredentials      *credentials,
323                                  gpointer           user_data)
324 {
325   PeerData *data = user_data;
326   gboolean authorized;
327 
328   data->num_connection_attempts++;
329 
330   authorized = TRUE;
331   if (!data->accept_connection)
332     {
333       authorized = FALSE;
334       g_main_loop_quit (loop);
335     }
336 
337   return authorized;
338 }
339 
340 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
341 static gboolean
on_new_connection(GDBusServer * server,GDBusConnection * connection,gpointer user_data)342 on_new_connection (GDBusServer *server,
343                    GDBusConnection *connection,
344                    gpointer user_data)
345 {
346   PeerData *data = user_data;
347   GError *error;
348   guint reg_id;
349 
350   //g_printerr ("Client connected.\n"
351   //         "Negotiated capabilities: unix-fd-passing=%d\n",
352   //         g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
353 
354   g_ptr_array_add (data->current_connections, g_object_ref (connection));
355 
356 #if G_CREDENTIALS_SUPPORTED
357     {
358       GCredentials *credentials;
359 
360       credentials = g_dbus_connection_get_peer_credentials (connection);
361 
362       g_assert (credentials != NULL);
363       g_assert_cmpuint (g_credentials_get_unix_user (credentials, NULL), ==,
364                         getuid ());
365       g_assert_cmpuint (g_credentials_get_unix_pid (credentials, NULL), ==,
366                         getpid ());
367     }
368 #endif
369 
370   /* export object on the newly established connection */
371   error = NULL;
372   reg_id = g_dbus_connection_register_object (connection,
373                                               "/org/gtk/GDBus/PeerTestObject",
374                                               test_interface_introspection_data,
375                                               &test_interface_vtable,
376                                               data,
377                                               NULL, /* GDestroyNotify for data */
378                                               &error);
379   g_assert_no_error (error);
380   g_assert (reg_id > 0);
381 
382   g_main_loop_quit (loop);
383 
384   return TRUE;
385 }
386 
387 /* We don't tell the main thread about the new GDBusServer until it has
388  * had a chance to start listening. */
389 static gboolean
idle_in_service_loop(gpointer loop)390 idle_in_service_loop (gpointer loop)
391 {
392   g_assert (service_loop == NULL);
393   g_mutex_lock (&service_loop_lock);
394   service_loop = loop;
395   g_cond_broadcast (&service_loop_cond);
396   g_mutex_unlock (&service_loop_lock);
397 
398   return G_SOURCE_REMOVE;
399 }
400 
401 static void
run_service_loop(GMainContext * service_context)402 run_service_loop (GMainContext *service_context)
403 {
404   GMainLoop *loop;
405   GSource *source;
406 
407   g_assert (service_loop == NULL);
408 
409   loop = g_main_loop_new (service_context, FALSE);
410   source = g_idle_source_new ();
411   g_source_set_callback (source, idle_in_service_loop, loop, NULL);
412   g_source_attach (source, service_context);
413   g_source_unref (source);
414   g_main_loop_run (loop);
415 }
416 
417 static void
teardown_service_loop(void)418 teardown_service_loop (void)
419 {
420   g_mutex_lock (&service_loop_lock);
421   g_clear_pointer (&service_loop, g_main_loop_unref);
422   g_mutex_unlock (&service_loop_lock);
423 }
424 
425 static void
await_service_loop(void)426 await_service_loop (void)
427 {
428   g_mutex_lock (&service_loop_lock);
429   while (service_loop == NULL)
430     g_cond_wait (&service_loop_cond, &service_loop_lock);
431   g_mutex_unlock (&service_loop_lock);
432 }
433 
434 static gpointer
service_thread_func(gpointer user_data)435 service_thread_func (gpointer user_data)
436 {
437   PeerData *data = user_data;
438   GMainContext *service_context;
439   GDBusAuthObserver *observer, *o;
440   GError *error;
441   GDBusServerFlags f;
442   gchar *a, *g;
443   gboolean b;
444 
445   service_context = g_main_context_new ();
446   g_main_context_push_thread_default (service_context);
447 
448   error = NULL;
449   observer = g_dbus_auth_observer_new ();
450   server = g_dbus_server_new_sync (tmp_address,
451                                    G_DBUS_SERVER_FLAGS_NONE,
452                                    test_guid,
453                                    observer,
454                                    NULL, /* cancellable */
455                                    &error);
456   g_assert_no_error (error);
457 
458   g_signal_connect (server,
459                     "new-connection",
460                     G_CALLBACK (on_new_connection),
461                     data);
462   g_signal_connect (observer,
463                     "authorize-authenticated-peer",
464                     G_CALLBACK (on_authorize_authenticated_peer),
465                     data);
466 
467   g_assert_cmpint (g_dbus_server_get_flags (server), ==, G_DBUS_SERVER_FLAGS_NONE);
468   g_assert_cmpstr (g_dbus_server_get_guid (server), ==, test_guid);
469   g_object_get (server,
470                 "flags", &f,
471                 "address", &a,
472                 "guid", &g,
473                 "active", &b,
474                 "authentication-observer", &o,
475                 NULL);
476   g_assert_cmpint (f, ==, G_DBUS_SERVER_FLAGS_NONE);
477   g_assert_cmpstr (a, ==, tmp_address);
478   g_assert_cmpstr (g, ==, test_guid);
479   g_assert (!b);
480   g_assert (o == observer);
481   g_free (a);
482   g_free (g);
483   g_object_unref (o);
484 
485   g_object_unref (observer);
486 
487   g_dbus_server_start (server);
488 
489   run_service_loop (service_context);
490 
491   g_main_context_pop_thread_default (service_context);
492 
493   teardown_service_loop ();
494   g_main_context_unref (service_context);
495 
496   /* test code specifically unrefs the server - see below */
497   g_assert (server == NULL);
498 
499   return NULL;
500 }
501 
502 #if 0
503 static gboolean
504 on_incoming_connection (GSocketService     *service,
505                         GSocketConnection  *socket_connection,
506                         GObject            *source_object,
507                         gpointer           user_data)
508 {
509   PeerData *data = user_data;
510 
511   if (data->accept_connection)
512     {
513       GError *error;
514       guint reg_id;
515       GDBusConnection *connection;
516 
517       error = NULL;
518       connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
519                                                test_guid,
520                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
521                                                NULL, /* cancellable */
522                                                &error);
523       g_assert_no_error (error);
524 
525       g_ptr_array_add (data->current_connections, connection);
526 
527       /* export object on the newly established connection */
528       error = NULL;
529       reg_id = g_dbus_connection_register_object (connection,
530                                                   "/org/gtk/GDBus/PeerTestObject",
531                                                   &test_interface_introspection_data,
532                                                   &test_interface_vtable,
533                                                   data,
534                                                   NULL, /* GDestroyNotify for data */
535                                                   &error);
536       g_assert_no_error (error);
537       g_assert (reg_id > 0);
538 
539     }
540   else
541     {
542       /* don't do anything */
543     }
544 
545   data->num_connection_attempts++;
546 
547   g_main_loop_quit (loop);
548 
549   /* stops other signal handlers from being invoked */
550   return TRUE;
551 }
552 
553 static gpointer
554 service_thread_func (gpointer data)
555 {
556   GMainContext *service_context;
557   gchar *socket_path;
558   GSocketAddress *address;
559   GError *error;
560 
561   service_context = g_main_context_new ();
562   g_main_context_push_thread_default (service_context);
563 
564   socket_path = g_strdup_printf ("/tmp/gdbus-test-pid-%d", getpid ());
565   address = g_unix_socket_address_new (socket_path);
566 
567   service = g_socket_service_new ();
568   error = NULL;
569   g_socket_listener_add_address (G_SOCKET_LISTENER (service),
570                                  address,
571                                  G_SOCKET_TYPE_STREAM,
572                                  G_SOCKET_PROTOCOL_DEFAULT,
573                                  NULL, /* source_object */
574                                  NULL, /* effective_address */
575                                  &error);
576   g_assert_no_error (error);
577   g_signal_connect (service,
578                     "incoming",
579                     G_CALLBACK (on_incoming_connection),
580                     data);
581   g_socket_service_start (service);
582 
583   run_service_loop (service_context);
584 
585   g_main_context_pop_thread_default (service_context);
586 
587   teardown_service_loop ();
588   g_main_context_unref (service_context);
589 
590   g_object_unref (address);
591   g_free (socket_path);
592   return NULL;
593 }
594 #endif
595 
596 /* ---------------------------------------------------------------------------------------------------- */
597 
598 #if 0
599 static gboolean
600 check_connection (gpointer user_data)
601 {
602   PeerData *data = user_data;
603   guint n;
604 
605   for (n = 0; n < data->current_connections->len; n++)
606     {
607       GDBusConnection *c;
608       GIOStream *stream;
609 
610       c = G_DBUS_CONNECTION (data->current_connections->pdata[n]);
611       stream = g_dbus_connection_get_stream (c);
612 
613       g_debug ("In check_connection for %d: connection %p, stream %p", n, c, stream);
614       g_debug ("closed = %d", g_io_stream_is_closed (stream));
615 
616       GSocket *socket;
617       socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
618       g_debug ("socket_closed = %d", g_socket_is_closed (socket));
619       g_debug ("socket_condition_check = %d", g_socket_condition_check (socket, G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP));
620 
621       gchar buf[128];
622       GError *error;
623       gssize num_read;
624       error = NULL;
625       num_read = g_input_stream_read (g_io_stream_get_input_stream (stream),
626                                       buf,
627                                       128,
628                                       NULL,
629                                       &error);
630       if (num_read < 0)
631         {
632           g_debug ("error: %s", error->message);
633           g_error_free (error);
634         }
635       else
636         {
637           g_debug ("no error, read %d bytes", (gint) num_read);
638         }
639     }
640 
641   return FALSE;
642 }
643 
644 static gboolean
645 on_do_disconnect_in_idle (gpointer data)
646 {
647   GDBusConnection *c = G_DBUS_CONNECTION (data);
648   g_debug ("GDC %p has ref_count %d", c, G_OBJECT (c)->ref_count);
649   g_dbus_connection_disconnect (c);
650   g_object_unref (c);
651   return FALSE;
652 }
653 #endif
654 
655 #ifdef G_OS_UNIX
656 static gchar *
read_all_from_fd(gint fd,gsize * out_len,GError ** error)657 read_all_from_fd (gint fd, gsize *out_len, GError **error)
658 {
659   GString *str;
660   gchar buf[64];
661   gssize num_read;
662 
663   str = g_string_new (NULL);
664 
665   do
666     {
667       int errsv;
668 
669       num_read = read (fd, buf, sizeof (buf));
670       errsv = errno;
671       if (num_read == -1)
672         {
673           if (errsv == EAGAIN || errsv == EWOULDBLOCK)
674             continue;
675           g_set_error (error,
676                        G_IO_ERROR,
677                        g_io_error_from_errno (errsv),
678                        "Failed reading %d bytes into offset %d: %s",
679                        (gint) sizeof (buf),
680                        (gint) str->len,
681                        g_strerror (errsv));
682           goto error;
683         }
684       else if (num_read > 0)
685         {
686           g_string_append_len (str, buf, num_read);
687         }
688       else if (num_read == 0)
689         {
690           break;
691         }
692     }
693   while (TRUE);
694 
695   if (out_len != NULL)
696     *out_len = str->len;
697   return g_string_free (str, FALSE);
698 
699  error:
700   if (out_len != NULL)
701     *out_len = 0;
702   g_string_free (str, TRUE);
703   return NULL;
704 }
705 #endif
706 
707 static void
do_test_peer(void)708 do_test_peer (void)
709 {
710   GDBusConnection *c;
711   GDBusConnection *c2;
712   GDBusProxy *proxy;
713   GError *error;
714   PeerData data;
715   GVariant *value;
716   GVariant *result;
717   const gchar *s;
718   GThread *service_thread;
719   gulong signal_handler_id;
720 
721   memset (&data, '\0', sizeof (PeerData));
722   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
723 
724   /* first try to connect when there is no server */
725   error = NULL;
726   c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" :
727                                               /* NOTE: Even if something is listening on port 12345 the connection
728                                                * will fail because the nonce file doesn't exist */
729                                               "nonce-tcp:host=127.0.0.1,port=12345,noncefile=this-does-not-exist-gdbus",
730                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
731                                               NULL, /* GDBusAuthObserver */
732                                               NULL, /* cancellable */
733                                               &error);
734   _g_assert_error_domain (error, G_IO_ERROR);
735   g_assert (!g_dbus_error_is_remote_error (error));
736   g_clear_error (&error);
737   g_assert (c == NULL);
738 
739   /* bring up a server - we run the server in a different thread to avoid deadlocks */
740   service_thread = g_thread_new ("test_peer",
741                                  service_thread_func,
742                                  &data);
743   await_service_loop ();
744   g_assert (server != NULL);
745 
746   /* bring up a connection and accept it */
747   data.accept_connection = TRUE;
748   error = NULL;
749   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
750                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
751                                               NULL, /* GDBusAuthObserver */
752                                               NULL, /* cancellable */
753                                               &error);
754   g_assert_no_error (error);
755   g_assert (c != NULL);
756   while (data.current_connections->len < 1)
757     g_main_loop_run (loop);
758   g_assert_cmpint (data.current_connections->len, ==, 1);
759   g_assert_cmpint (data.num_connection_attempts, ==, 1);
760   g_assert (g_dbus_connection_get_unique_name (c) == NULL);
761   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
762 
763   /* check that we create a proxy, read properties, receive signals and invoke
764    * the HelloPeer() method. Since the server runs in another thread it's fine
765    * to use synchronous blocking API here.
766    */
767   error = NULL;
768   proxy = g_dbus_proxy_new_sync (c,
769                                  G_DBUS_PROXY_FLAGS_NONE,
770                                  NULL,
771                                  NULL, /* bus_name */
772                                  "/org/gtk/GDBus/PeerTestObject",
773                                  "org.gtk.GDBus.PeerTestInterface",
774                                  NULL, /* GCancellable */
775                                  &error);
776   g_assert_no_error (error);
777   g_assert (proxy != NULL);
778   error = NULL;
779   value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
780   g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
781 
782   /* try invoking a method */
783   error = NULL;
784   result = g_dbus_proxy_call_sync (proxy,
785                                    "HelloPeer",
786                                    g_variant_new ("(s)", "Hey Peer!"),
787                                    G_DBUS_CALL_FLAGS_NONE,
788                                    -1,
789                                    NULL,  /* GCancellable */
790                                    &error);
791   g_assert_no_error (error);
792   g_variant_get (result, "(&s)", &s);
793   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Peer!'.");
794   g_variant_unref (result);
795   g_assert_cmpint (data.num_method_calls, ==, 1);
796 
797   /* make the other peer emit a signal - catch it */
798   signal_handler_id = g_signal_connect (proxy,
799                                         "g-signal",
800                                         G_CALLBACK (on_proxy_signal_received),
801                                         &data);
802   g_assert (!data.signal_received);
803   g_dbus_proxy_call (proxy,
804                      "EmitSignal",
805                      NULL,  /* no arguments */
806                      G_DBUS_CALL_FLAGS_NONE,
807                      -1,
808                      NULL,  /* GCancellable */
809                      NULL,  /* GAsyncReadyCallback - we don't care about the result */
810                      NULL); /* user_data */
811   g_main_loop_run (loop);
812   g_assert (data.signal_received);
813   g_assert_cmpint (data.num_method_calls, ==, 2);
814   g_signal_handler_disconnect (proxy, signal_handler_id);
815 
816   /* Also ensure that messages with the sender header-field set gets
817    * delivered to the proxy - note that this doesn't really make sense
818    * e.g. names are meaning-less in a peer-to-peer case... but we
819    * support it because it makes sense in certain bridging
820    * applications - see e.g. #623815.
821    */
822   signal_handler_id = g_signal_connect (proxy,
823                                         "g-signal",
824                                         G_CALLBACK (on_proxy_signal_received_with_name_set),
825                                         &data);
826   data.signal_received = FALSE;
827   g_dbus_proxy_call (proxy,
828                      "EmitSignalWithNameSet",
829                      NULL,  /* no arguments */
830                      G_DBUS_CALL_FLAGS_NONE,
831                      -1,
832                      NULL,  /* GCancellable */
833                      NULL,  /* GAsyncReadyCallback - we don't care about the result */
834                      NULL); /* user_data */
835   g_main_loop_run (loop);
836   g_assert (data.signal_received);
837   g_assert_cmpint (data.num_method_calls, ==, 3);
838   g_signal_handler_disconnect (proxy, signal_handler_id);
839 
840   /* check for UNIX fd passing */
841 #ifdef G_OS_UNIX
842   {
843     GDBusMessage *method_call_message;
844     GDBusMessage *method_reply_message;
845     GUnixFDList *fd_list;
846     gint fd;
847     gchar *buf;
848     gsize len;
849     gchar *buf2;
850     gsize len2;
851     const char *testfile = g_test_get_filename (G_TEST_DIST, "file.c", NULL);
852 
853     method_call_message = g_dbus_message_new_method_call (NULL, /* name */
854                                                           "/org/gtk/GDBus/PeerTestObject",
855                                                           "org.gtk.GDBus.PeerTestInterface",
856                                                           "OpenFile");
857     g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", testfile));
858     error = NULL;
859     method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
860                                                                            method_call_message,
861                                                                            G_DBUS_SEND_MESSAGE_FLAGS_NONE,
862                                                                            -1,
863                                                                            NULL, /* out_serial */
864                                                                            NULL, /* cancellable */
865                                                                            &error);
866     g_assert_no_error (error);
867     g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
868     fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
869     g_assert (fd_list != NULL);
870     g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
871     error = NULL;
872     fd = g_unix_fd_list_get (fd_list, 0, &error);
873     g_assert_no_error (error);
874     g_object_unref (method_call_message);
875     g_object_unref (method_reply_message);
876 
877     error = NULL;
878     len = 0;
879     buf = read_all_from_fd (fd, &len, &error);
880     g_assert_no_error (error);
881     g_assert (buf != NULL);
882     close (fd);
883 
884     error = NULL;
885     g_file_get_contents (testfile,
886                          &buf2,
887                          &len2,
888                          &error);
889     g_assert_no_error (error);
890     g_assert_cmpmem (buf, len, buf2, len2);
891     g_free (buf2);
892     g_free (buf);
893   }
894 #else
895   error = NULL;
896   result = g_dbus_proxy_call_sync (proxy,
897                                    "OpenFile",
898                                    g_variant_new ("(s)", "boo"),
899                                    G_DBUS_CALL_FLAGS_NONE,
900                                    -1,
901                                    NULL,  /* GCancellable */
902                                    &error);
903   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
904   g_assert (result == NULL);
905   g_error_free (error);
906 #endif /* G_OS_UNIX */
907 
908   /* Check that g_socket_get_credentials() work - (though this really
909    * should be in socket.c)
910    */
911   {
912     GSocket *socket;
913     GCredentials *credentials;
914     socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (g_dbus_connection_get_stream (c)));
915     g_assert (G_IS_SOCKET (socket));
916     error = NULL;
917     credentials = g_socket_get_credentials (socket, &error);
918 
919 #if G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED
920     g_assert_no_error (error);
921     g_assert (G_IS_CREDENTIALS (credentials));
922 
923     g_assert_cmpuint (g_credentials_get_unix_user (credentials, NULL), ==,
924                       getuid ());
925     g_assert_cmpuint (g_credentials_get_unix_pid (credentials, NULL), ==,
926                       getpid ());
927     g_object_unref (credentials);
928 #else
929     g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
930     g_assert (credentials == NULL);
931 #endif
932   }
933 
934 
935   /* bring up a connection - don't accept it - this should fail
936    */
937   data.accept_connection = FALSE;
938   error = NULL;
939   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
940                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
941                                                NULL, /* GDBusAuthObserver */
942                                                NULL, /* cancellable */
943                                                &error);
944   _g_assert_error_domain (error, G_IO_ERROR);
945   g_error_free (error);
946   g_assert (c2 == NULL);
947 
948 #if 0
949   /* TODO: THIS TEST DOESN'T WORK YET */
950 
951   /* bring up a connection - accept it.. then disconnect from the client side - check
952    * that the server side gets the disconnect signal.
953    */
954   error = NULL;
955   data.accept_connection = TRUE;
956   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
957                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
958                                                NULL, /* GDBusAuthObserver */
959                                                NULL, /* cancellable */
960                                                &error);
961   g_assert_no_error (error);
962   g_assert (c2 != NULL);
963   g_assert (!g_dbus_connection_get_is_disconnected (c2));
964   while (data.num_connection_attempts < 3)
965     g_main_loop_run (loop);
966   g_assert_cmpint (data.current_connections->len, ==, 2);
967   g_assert_cmpint (data.num_connection_attempts, ==, 3);
968   g_assert (!g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
969   g_idle_add (on_do_disconnect_in_idle, c2);
970   g_debug ("==================================================");
971   g_debug ("==================================================");
972   g_debug ("==================================================");
973   g_debug ("waiting for disconnect on connection %p, stream %p",
974            data.current_connections->pdata[1],
975            g_dbus_connection_get_stream (data.current_connections->pdata[1]));
976 
977   g_timeout_add (2000, check_connection, &data);
978   //_g_assert_signal_received (G_DBUS_CONNECTION (data.current_connections->pdata[1]), "closed");
979   g_main_loop_run (loop);
980   g_assert (g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
981   g_ptr_array_set_size (data.current_connections, 1); /* remove disconnected connection object */
982 #endif
983 
984   /* unref the server and stop listening for new connections
985    *
986    * This won't bring down the established connections - check that c is still connected
987    * by invoking a method
988    */
989   //g_socket_service_stop (service);
990   //g_object_unref (service);
991   g_dbus_server_stop (server);
992   g_object_unref (server);
993   server = NULL;
994 
995   error = NULL;
996   result = g_dbus_proxy_call_sync (proxy,
997                                    "HelloPeer",
998                                    g_variant_new ("(s)", "Hey Again Peer!"),
999                                    G_DBUS_CALL_FLAGS_NONE,
1000                                    -1,
1001                                    NULL,  /* GCancellable */
1002                                    &error);
1003   g_assert_no_error (error);
1004   g_variant_get (result, "(&s)", &s);
1005   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
1006   g_variant_unref (result);
1007   g_assert_cmpint (data.num_method_calls, ==, 5);
1008 
1009 #if 0
1010   /* TODO: THIS TEST DOESN'T WORK YET */
1011 
1012   /* now disconnect from the server side - check that the client side gets the signal */
1013   g_assert_cmpint (data.current_connections->len, ==, 1);
1014   g_assert (G_DBUS_CONNECTION (data.current_connections->pdata[0]) != c);
1015   g_dbus_connection_disconnect (G_DBUS_CONNECTION (data.current_connections->pdata[0]));
1016   if (!g_dbus_connection_get_is_disconnected (c))
1017     _g_assert_signal_received (c, "closed");
1018   g_assert (g_dbus_connection_get_is_disconnected (c));
1019 #endif
1020 
1021   g_object_unref (c);
1022   g_ptr_array_unref (data.current_connections);
1023   g_object_unref (proxy);
1024 
1025   g_main_loop_quit (service_loop);
1026   g_thread_join (service_thread);
1027 }
1028 
1029 static void
test_peer(void)1030 test_peer (void)
1031 {
1032   test_guid = g_dbus_generate_guid ();
1033   loop = g_main_loop_new (NULL, FALSE);
1034 
1035   /* Run this test multiple times using different address formats to ensure
1036    * they all work.
1037    */
1038   setup_test_address ();
1039   do_test_peer ();
1040   teardown_test_address ();
1041 
1042 #ifdef G_OS_UNIX
1043   setup_tmpdir_test_address ();
1044   do_test_peer ();
1045   teardown_test_address ();
1046 
1047   setup_path_test_address ();
1048   do_test_peer ();
1049   teardown_test_address ();
1050 #endif
1051 
1052   g_main_loop_unref (loop);
1053   g_free (test_guid);
1054 }
1055 
1056 /* ---------------------------------------------------------------------------------------------------- */
1057 
1058 static void
test_peer_signals(void)1059 test_peer_signals (void)
1060 {
1061   GDBusConnection *c;
1062   GDBusProxy *proxy;
1063   GError *error = NULL;
1064   PeerData data;
1065   GThread *service_thread;
1066 
1067   g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1620");
1068 
1069   test_guid = g_dbus_generate_guid ();
1070   loop = g_main_loop_new (NULL, FALSE);
1071 
1072   setup_test_address ();
1073   memset (&data, '\0', sizeof (PeerData));
1074   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
1075 
1076   /* bring up a server - we run the server in a different thread to avoid deadlocks */
1077   service_thread = g_thread_new ("test_peer",
1078                                  service_thread_func,
1079                                  &data);
1080   await_service_loop ();
1081   g_assert_nonnull (server);
1082 
1083   /* bring up a connection and accept it */
1084   data.accept_connection = TRUE;
1085   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
1086                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1087                                               NULL, /* GDBusAuthObserver */
1088                                               NULL, /* cancellable */
1089                                               &error);
1090   g_assert_no_error (error);
1091   g_assert_nonnull (c);
1092   while (data.current_connections->len < 1)
1093     g_main_loop_run (loop);
1094   g_assert_cmpint (data.current_connections->len, ==, 1);
1095   g_assert_cmpint (data.num_connection_attempts, ==, 1);
1096   g_assert_null (g_dbus_connection_get_unique_name (c));
1097   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
1098 
1099   /* Check that we can create a proxy with a non-NULL bus name, even though it's
1100    * irrelevant in the non-message-bus case. Since the server runs in another
1101    * thread it's fine to use synchronous blocking API here.
1102    */
1103   proxy = g_dbus_proxy_new_sync (c,
1104                                  G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1105                                  G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1106                                  NULL,
1107                                  ":1.1", /* bus_name */
1108                                  "/org/gtk/GDBus/PeerTestObject",
1109                                  "org.gtk.GDBus.PeerTestInterface",
1110                                  NULL, /* GCancellable */
1111                                  &error);
1112   g_assert_no_error (error);
1113   g_assert_nonnull (proxy);
1114 
1115   /* unref the server and stop listening for new connections */
1116   g_dbus_server_stop (server);
1117   g_clear_object (&server);
1118 
1119   g_object_unref (c);
1120   g_ptr_array_unref (data.current_connections);
1121   g_object_unref (proxy);
1122 
1123   g_main_loop_quit (service_loop);
1124   g_thread_join (service_thread);
1125 
1126   teardown_test_address ();
1127 
1128   g_main_loop_unref (loop);
1129   g_free (test_guid);
1130 }
1131 
1132 /* ---------------------------------------------------------------------------------------------------- */
1133 
1134 typedef struct
1135 {
1136   GDBusServer *server;
1137   GMainContext *context;
1138   GMainLoop *loop;
1139 
1140   GList *connections;
1141 } DmpData;
1142 
1143 static void
dmp_data_free(DmpData * data)1144 dmp_data_free (DmpData *data)
1145 {
1146   g_main_loop_unref (data->loop);
1147   g_main_context_unref (data->context);
1148   g_object_unref (data->server);
1149   g_list_free_full (data->connections, g_object_unref);
1150   g_free (data);
1151 }
1152 
1153 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)1154 dmp_on_method_call (GDBusConnection       *connection,
1155                     const gchar           *sender,
1156                     const gchar           *object_path,
1157                     const gchar           *interface_name,
1158                     const gchar           *method_name,
1159                     GVariant              *parameters,
1160                     GDBusMethodInvocation *invocation,
1161                     gpointer               user_data)
1162 {
1163   //DmpData *data = user_data;
1164   gint32 first;
1165   gint32 second;
1166   g_variant_get (parameters,
1167                  "(ii)",
1168                  &first,
1169                  &second);
1170   g_dbus_method_invocation_return_value (invocation,
1171                                          g_variant_new ("(i)", first + second));
1172 }
1173 
1174 static const GDBusInterfaceVTable dmp_interface_vtable =
1175 {
1176   dmp_on_method_call,
1177   NULL,  /* get_property */
1178   NULL   /* set_property */
1179 };
1180 
1181 
1182 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
1183 static gboolean
dmp_on_new_connection(GDBusServer * server,GDBusConnection * connection,gpointer user_data)1184 dmp_on_new_connection (GDBusServer     *server,
1185                        GDBusConnection *connection,
1186                        gpointer         user_data)
1187 {
1188   DmpData *data = user_data;
1189   GDBusNodeInfo *node;
1190   GError *error;
1191 
1192   /* accept the connection */
1193   data->connections = g_list_prepend (data->connections, g_object_ref (connection));
1194 
1195   error = NULL;
1196   node = g_dbus_node_info_new_for_xml ("<node>"
1197                                        "  <interface name='org.gtk.GDBus.DmpInterface'>"
1198                                        "    <method name='AddPair'>"
1199                                        "      <arg type='i' name='first' direction='in'/>"
1200                                        "      <arg type='i' name='second' direction='in'/>"
1201                                        "      <arg type='i' name='sum' direction='out'/>"
1202                                        "    </method>"
1203                                        "  </interface>"
1204                                        "</node>",
1205                                        &error);
1206   g_assert_no_error (error);
1207 
1208   /* sleep 100ms before exporting an object - this is to test that
1209    * G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING really works
1210    * (GDBusServer uses this feature).
1211    */
1212   usleep (100 * 1000);
1213 
1214   /* export an object */
1215   error = NULL;
1216   g_dbus_connection_register_object (connection,
1217                                      "/dmp/test",
1218                                      node->interfaces[0],
1219                                      &dmp_interface_vtable,
1220                                      data,
1221                                      NULL,
1222                                      &error);
1223   g_dbus_node_info_unref (node);
1224 
1225   return TRUE;
1226 }
1227 
1228 static gpointer
dmp_thread_func(gpointer user_data)1229 dmp_thread_func (gpointer user_data)
1230 {
1231   DmpData *data = user_data;
1232   GError *error;
1233   gchar *guid;
1234 
1235   data->context = g_main_context_new ();
1236   g_main_context_push_thread_default (data->context);
1237 
1238   error = NULL;
1239   guid = g_dbus_generate_guid ();
1240   data->server = g_dbus_server_new_sync (tmp_address,
1241                                          G_DBUS_SERVER_FLAGS_NONE,
1242                                          guid,
1243                                          NULL, /* GDBusAuthObserver */
1244                                          NULL, /* GCancellable */
1245                                          &error);
1246   g_assert_no_error (error);
1247   g_signal_connect (data->server,
1248                     "new-connection",
1249                     G_CALLBACK (dmp_on_new_connection),
1250                     data);
1251 
1252   g_dbus_server_start (data->server);
1253 
1254   data->loop = g_main_loop_new (data->context, FALSE);
1255   g_main_loop_run (data->loop);
1256 
1257   g_dbus_server_stop (data->server);
1258   g_main_context_pop_thread_default (data->context);
1259 
1260   g_free (guid);
1261   return NULL;
1262 }
1263 
1264 static void
delayed_message_processing(void)1265 delayed_message_processing (void)
1266 {
1267   GError *error;
1268   DmpData *data;
1269   GThread *service_thread;
1270   guint n;
1271 
1272   test_guid = g_dbus_generate_guid ();
1273   loop = g_main_loop_new (NULL, FALSE);
1274 
1275   setup_test_address ();
1276 
1277   data = g_new0 (DmpData, 1);
1278 
1279   service_thread = g_thread_new ("dmp",
1280                                  dmp_thread_func,
1281                                  data);
1282   while (data->server == NULL || !g_dbus_server_is_active (data->server))
1283     g_thread_yield ();
1284 
1285   for (n = 0; n < 5; n++)
1286     {
1287       GDBusConnection *c;
1288       GVariant *res;
1289       gint32 val;
1290 
1291       error = NULL;
1292       c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data->server),
1293                                                   G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1294                                                   NULL, /* GDBusAuthObserver */
1295                                                   NULL, /* GCancellable */
1296                                                   &error);
1297       g_assert_no_error (error);
1298 
1299       error = NULL;
1300       res = g_dbus_connection_call_sync (c,
1301                                          NULL,    /* bus name */
1302                                          "/dmp/test",
1303                                          "org.gtk.GDBus.DmpInterface",
1304                                          "AddPair",
1305                                          g_variant_new ("(ii)", 2, n),
1306                                          G_VARIANT_TYPE ("(i)"),
1307                                          G_DBUS_CALL_FLAGS_NONE,
1308                                          -1, /* timeout_msec */
1309                                          NULL, /* GCancellable */
1310                                          &error);
1311       g_assert_no_error (error);
1312       g_variant_get (res, "(i)", &val);
1313       g_assert_cmpint (val, ==, 2 + n);
1314       g_variant_unref (res);
1315       g_object_unref (c);
1316   }
1317 
1318   g_main_loop_quit (data->loop);
1319   g_thread_join (service_thread);
1320   dmp_data_free (data);
1321   teardown_test_address ();
1322 
1323   g_main_loop_unref (loop);
1324   g_free (test_guid);
1325 }
1326 
1327 /* ---------------------------------------------------------------------------------------------------- */
1328 
1329 static gboolean
nonce_tcp_on_authorize_authenticated_peer(GDBusAuthObserver * observer,GIOStream * stream,GCredentials * credentials,gpointer user_data)1330 nonce_tcp_on_authorize_authenticated_peer (GDBusAuthObserver *observer,
1331                                            GIOStream         *stream,
1332                                            GCredentials      *credentials,
1333                                            gpointer           user_data)
1334 {
1335   PeerData *data = user_data;
1336   gboolean authorized;
1337 
1338   data->num_connection_attempts++;
1339 
1340   authorized = TRUE;
1341   if (!data->accept_connection)
1342     {
1343       authorized = FALSE;
1344       g_main_loop_quit (loop);
1345     }
1346 
1347   return authorized;
1348 }
1349 
1350 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
1351 static gboolean
nonce_tcp_on_new_connection(GDBusServer * server,GDBusConnection * connection,gpointer user_data)1352 nonce_tcp_on_new_connection (GDBusServer *server,
1353                              GDBusConnection *connection,
1354                              gpointer user_data)
1355 {
1356   PeerData *data = user_data;
1357 
1358   g_ptr_array_add (data->current_connections, g_object_ref (connection));
1359 
1360   g_main_loop_quit (loop);
1361 
1362   return TRUE;
1363 }
1364 
1365 static gpointer
nonce_tcp_service_thread_func(gpointer user_data)1366 nonce_tcp_service_thread_func (gpointer user_data)
1367 {
1368   PeerData *data = user_data;
1369   GMainContext *service_context;
1370   GDBusAuthObserver *observer;
1371   GError *error;
1372 
1373   service_context = g_main_context_new ();
1374   g_main_context_push_thread_default (service_context);
1375 
1376   error = NULL;
1377   observer = g_dbus_auth_observer_new ();
1378   server = g_dbus_server_new_sync ("nonce-tcp:host=127.0.0.1",
1379                                    G_DBUS_SERVER_FLAGS_NONE,
1380                                    test_guid,
1381                                    observer,
1382                                    NULL, /* cancellable */
1383                                    &error);
1384   g_assert_no_error (error);
1385 
1386   g_signal_connect (server,
1387                     "new-connection",
1388                     G_CALLBACK (nonce_tcp_on_new_connection),
1389                     data);
1390   g_signal_connect (observer,
1391                     "authorize-authenticated-peer",
1392                     G_CALLBACK (nonce_tcp_on_authorize_authenticated_peer),
1393                     data);
1394   g_object_unref (observer);
1395 
1396   g_dbus_server_start (server);
1397 
1398   run_service_loop (service_context);
1399 
1400   g_main_context_pop_thread_default (service_context);
1401 
1402   teardown_service_loop ();
1403   g_main_context_unref (service_context);
1404 
1405   /* test code specifically unrefs the server - see below */
1406   g_assert (server == NULL);
1407 
1408   return NULL;
1409 }
1410 
1411 static void
test_nonce_tcp(void)1412 test_nonce_tcp (void)
1413 {
1414   PeerData data;
1415   GError *error;
1416   GThread *service_thread;
1417   GDBusConnection *c;
1418   gchar *s;
1419   gchar *nonce_file;
1420   gboolean res;
1421   const gchar *address;
1422 
1423   test_guid = g_dbus_generate_guid ();
1424   loop = g_main_loop_new (NULL, FALSE);
1425 
1426   memset (&data, '\0', sizeof (PeerData));
1427   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
1428 
1429   error = NULL;
1430   server = NULL;
1431   service_thread = g_thread_new ("nonce-tcp-service",
1432                                  nonce_tcp_service_thread_func,
1433                                  &data);
1434   await_service_loop ();
1435   g_assert (server != NULL);
1436 
1437   /* bring up a connection and accept it */
1438   data.accept_connection = TRUE;
1439   error = NULL;
1440   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
1441                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1442                                               NULL, /* GDBusAuthObserver */
1443                                               NULL, /* cancellable */
1444                                               &error);
1445   g_assert_no_error (error);
1446   g_assert (c != NULL);
1447   while (data.current_connections->len < 1)
1448     g_thread_yield ();
1449   g_assert_cmpint (data.current_connections->len, ==, 1);
1450   g_assert_cmpint (data.num_connection_attempts, ==, 1);
1451   g_assert (g_dbus_connection_get_unique_name (c) == NULL);
1452   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
1453   g_object_unref (c);
1454 
1455   /* now, try to subvert the nonce file (this assumes noncefile is the last key/value pair)
1456    */
1457 
1458   address = g_dbus_server_get_client_address (server);
1459 
1460   s = strstr (address, "noncefile=");
1461   g_assert (s != NULL);
1462   s += sizeof "noncefile=" - 1;
1463   nonce_file = g_strdup (s);
1464 
1465   /* First try invalid data in the nonce file - this will actually
1466    * make the client send this and the server will reject it. The way
1467    * it works is that if the nonce doesn't match, the server will
1468    * simply close the connection. So, from the client point of view,
1469    * we can see a variety of errors.
1470    */
1471   error = NULL;
1472   res = g_file_set_contents (nonce_file,
1473                              "0123456789012345",
1474                              -1,
1475                              &error);
1476   g_assert_no_error (error);
1477   g_assert (res);
1478   c = g_dbus_connection_new_for_address_sync (address,
1479                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1480                                               NULL, /* GDBusAuthObserver */
1481                                               NULL, /* cancellable */
1482                                               &error);
1483   _g_assert_error_domain (error, G_IO_ERROR);
1484   g_error_free (error);
1485   g_assert (c == NULL);
1486 
1487   /* Then try with a nonce-file of incorrect length - this will make
1488    * the client complain - we won't even try connecting to the server
1489    * for this
1490    */
1491   error = NULL;
1492   res = g_file_set_contents (nonce_file,
1493                              "0123456789012345_",
1494                              -1,
1495                              &error);
1496   g_assert_no_error (error);
1497   g_assert (res);
1498   c = g_dbus_connection_new_for_address_sync (address,
1499                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1500                                               NULL, /* GDBusAuthObserver */
1501                                               NULL, /* cancellable */
1502                                               &error);
1503   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1504   g_error_free (error);
1505   g_assert (c == NULL);
1506 
1507   /* Finally try with no nonce-file at all */
1508   g_assert_cmpint (g_unlink (nonce_file), ==, 0);
1509   error = NULL;
1510   c = g_dbus_connection_new_for_address_sync (address,
1511                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1512                                               NULL, /* GDBusAuthObserver */
1513                                               NULL, /* cancellable */
1514                                               &error);
1515   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1516   g_error_free (error);
1517   g_assert (c == NULL);
1518 
1519   /* Recreate the nonce-file so we can ensure the server deletes it when stopped. */
1520   g_assert_cmpint (g_creat (nonce_file, 0600), !=, -1);
1521 
1522   g_dbus_server_stop (server);
1523   g_object_unref (server);
1524   server = NULL;
1525 
1526   g_assert_false (g_file_test (nonce_file, G_FILE_TEST_EXISTS));
1527   g_free (nonce_file);
1528 
1529   g_main_loop_quit (service_loop);
1530   g_thread_join (service_thread);
1531 
1532   g_ptr_array_unref (data.current_connections);
1533 
1534   g_main_loop_unref (loop);
1535   g_free (test_guid);
1536 }
1537 
1538 static void
test_credentials(void)1539 test_credentials (void)
1540 {
1541   GCredentials *c1, *c2;
1542   GError *error;
1543   gchar *desc;
1544 
1545   c1 = g_credentials_new ();
1546   c2 = g_credentials_new ();
1547 
1548   error = NULL;
1549   if (g_credentials_set_unix_user (c2, getuid (), &error))
1550     g_assert_no_error (error);
1551 
1552   g_clear_error (&error);
1553   g_assert (g_credentials_is_same_user (c1, c2, &error));
1554   g_assert_no_error (error);
1555 
1556   desc = g_credentials_to_string (c1);
1557   g_assert (desc != NULL);
1558   g_free (desc);
1559 
1560   g_object_unref (c1);
1561   g_object_unref (c2);
1562 }
1563 
1564 /* ---------------------------------------------------------------------------------------------------- */
1565 
1566 static gboolean
tcp_anonymous_on_new_connection(GDBusServer * server,GDBusConnection * connection,gpointer user_data)1567 tcp_anonymous_on_new_connection (GDBusServer     *server,
1568                                  GDBusConnection *connection,
1569                                  gpointer         user_data)
1570 {
1571   gboolean *seen_connection = user_data;
1572   *seen_connection = TRUE;
1573   return TRUE;
1574 }
1575 
1576 static gpointer
tcp_anonymous_service_thread_func(gpointer user_data)1577 tcp_anonymous_service_thread_func (gpointer user_data)
1578 {
1579   gboolean *seen_connection = user_data;
1580   GMainContext *service_context;
1581   GError *error;
1582 
1583   service_context = g_main_context_new ();
1584   g_main_context_push_thread_default (service_context);
1585 
1586   error = NULL;
1587   server = g_dbus_server_new_sync ("tcp:host=127.0.0.1",
1588                                    G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS,
1589                                    test_guid,
1590                                    NULL, /* GDBusObserver* */
1591                                    NULL, /* GCancellable* */
1592                                    &error);
1593   g_assert_no_error (error);
1594 
1595   g_signal_connect (server,
1596                     "new-connection",
1597                     G_CALLBACK (tcp_anonymous_on_new_connection),
1598                     seen_connection);
1599 
1600   g_dbus_server_start (server);
1601 
1602   run_service_loop (service_context);
1603 
1604   g_main_context_pop_thread_default (service_context);
1605 
1606   teardown_service_loop ();
1607   g_main_context_unref (service_context);
1608 
1609   return NULL;
1610 }
1611 
1612 static void
test_tcp_anonymous(void)1613 test_tcp_anonymous (void)
1614 {
1615   gboolean seen_connection;
1616   GThread *service_thread;
1617   GDBusConnection *connection;
1618   GError *error;
1619 
1620   test_guid = g_dbus_generate_guid ();
1621   loop = g_main_loop_new (NULL, FALSE);
1622 
1623   seen_connection = FALSE;
1624   service_thread = g_thread_new ("tcp-anon-service",
1625                                  tcp_anonymous_service_thread_func,
1626                                  &seen_connection);
1627   await_service_loop ();
1628   g_assert (server != NULL);
1629 
1630   error = NULL;
1631   connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
1632                                                        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1633                                                        NULL, /* GDBusAuthObserver* */
1634                                                        NULL, /* GCancellable */
1635                                                        &error);
1636   g_assert_no_error (error);
1637   g_assert (connection != NULL);
1638 
1639   while (!seen_connection)
1640     g_thread_yield ();
1641 
1642   g_object_unref (connection);
1643 
1644   g_main_loop_quit (service_loop);
1645   g_dbus_server_stop (server);
1646   g_object_unref (server);
1647   server = NULL;
1648 
1649   g_thread_join (service_thread);
1650 
1651   g_main_loop_unref (loop);
1652   g_free (test_guid);
1653 }
1654 
1655 /* ---------------------------------------------------------------------------------------------------- */
1656 
1657 static GDBusServer *codegen_server = NULL;
1658 
1659 static gboolean
codegen_on_animal_poke(ExampleAnimal * animal,GDBusMethodInvocation * invocation,gboolean make_sad,gboolean make_happy,gpointer user_data)1660 codegen_on_animal_poke (ExampleAnimal          *animal,
1661                         GDBusMethodInvocation  *invocation,
1662                         gboolean                make_sad,
1663                         gboolean                make_happy,
1664                         gpointer                user_data)
1665 {
1666   if ((make_sad && make_happy) || (!make_sad && !make_happy))
1667     {
1668       g_main_loop_quit (service_loop);
1669 
1670       g_dbus_method_invocation_return_dbus_error (invocation,
1671                                                   "org.gtk.GDBus.Examples.ObjectManager.Error.Failed",
1672                                                   "Exactly one of make_sad or make_happy must be TRUE");
1673       goto out;
1674     }
1675 
1676   if (make_sad)
1677     {
1678       if (g_strcmp0 (example_animal_get_mood (animal), "Sad") == 0)
1679         {
1680           g_dbus_method_invocation_return_dbus_error (invocation,
1681                                                       "org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad",
1682                                                       "Sad animal is already sad");
1683           goto out;
1684         }
1685 
1686       example_animal_set_mood (animal, "Sad");
1687       example_animal_complete_poke (animal, invocation);
1688       goto out;
1689     }
1690 
1691   if (make_happy)
1692     {
1693       if (g_strcmp0 (example_animal_get_mood (animal), "Happy") == 0)
1694         {
1695           g_dbus_method_invocation_return_dbus_error (invocation,
1696                                                       "org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy",
1697                                                       "Happy animal is already happy");
1698           goto out;
1699         }
1700 
1701       example_animal_set_mood (animal, "Happy");
1702       example_animal_complete_poke (animal, invocation);
1703       goto out;
1704     }
1705 
1706   g_assert_not_reached ();
1707 
1708  out:
1709   return TRUE; /* to indicate that the method was handled */
1710 }
1711 
1712 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
1713 static gboolean
codegen_on_new_connection(GDBusServer * server,GDBusConnection * connection,gpointer user_data)1714 codegen_on_new_connection (GDBusServer *server,
1715                            GDBusConnection *connection,
1716                            gpointer user_data)
1717 {
1718   ExampleAnimal *animal = user_data;
1719   GError        *error = NULL;
1720 
1721   /* g_printerr ("Client connected.\n" */
1722   /*          "Negotiated capabilities: unix-fd-passing=%d\n", */
1723   /*          g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); */
1724 
1725   g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (animal), connection,
1726                                     "/Example/Animals/000", &error);
1727   g_assert_no_error (error);
1728 
1729   return TRUE;
1730 }
1731 
1732 static gpointer
codegen_service_thread_func(gpointer user_data)1733 codegen_service_thread_func (gpointer user_data)
1734 {
1735   GMainContext   *service_context;
1736   ExampleAnimal  *animal;
1737   GError         *error = NULL;
1738 
1739   service_context = g_main_context_new ();
1740   g_main_context_push_thread_default (service_context);
1741 
1742   /* Create the animal in the right thread context */
1743   animal = example_animal_skeleton_new ();
1744 
1745   /* Handle Poke() D-Bus method invocations on the .Animal interface */
1746   g_signal_connect (animal, "handle-poke",
1747                     G_CALLBACK (codegen_on_animal_poke),
1748                     NULL); /* user_data */
1749 
1750   codegen_server = g_dbus_server_new_sync (tmp_address,
1751                                            G_DBUS_SERVER_FLAGS_NONE,
1752                                            test_guid,
1753                                            NULL, /* observer */
1754                                            NULL, /* cancellable */
1755                                            &error);
1756   g_assert_no_error (error);
1757   g_dbus_server_start (codegen_server);
1758 
1759   g_signal_connect (codegen_server, "new-connection",
1760                     G_CALLBACK (codegen_on_new_connection),
1761                     animal);
1762 
1763   run_service_loop (service_context);
1764 
1765   g_object_unref (animal);
1766 
1767   g_main_context_pop_thread_default (service_context);
1768 
1769   teardown_service_loop ();
1770   g_main_context_unref (service_context);
1771 
1772   g_dbus_server_stop (codegen_server);
1773   g_object_unref (codegen_server);
1774   codegen_server = NULL;
1775 
1776   return NULL;
1777 }
1778 
1779 
1780 static gboolean
codegen_quit_mainloop_timeout(gpointer data)1781 codegen_quit_mainloop_timeout (gpointer data)
1782 {
1783   g_main_loop_quit (loop);
1784   return FALSE;
1785 }
1786 
1787 static void
codegen_test_peer(void)1788 codegen_test_peer (void)
1789 {
1790   GDBusConnection     *connection;
1791   ExampleAnimal       *animal1, *animal2;
1792   GThread             *service_thread;
1793   GError              *error = NULL;
1794   GVariant            *value;
1795   const gchar         *s;
1796 
1797   test_guid = g_dbus_generate_guid ();
1798   loop = g_main_loop_new (NULL, FALSE);
1799 
1800   setup_test_address ();
1801 
1802   /* bring up a server - we run the server in a different thread to avoid deadlocks */
1803   service_thread = g_thread_new ("codegen_test_peer",
1804                                  codegen_service_thread_func,
1805                                  NULL);
1806   await_service_loop ();
1807   g_assert (codegen_server != NULL);
1808 
1809   /* Get an animal 1 ...  */
1810   connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
1811                                                        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1812                                                        NULL, /* GDBusAuthObserver */
1813                                                        NULL, /* cancellable */
1814                                                        &error);
1815   g_assert_no_error (error);
1816   g_assert (connection != NULL);
1817 
1818   animal1 = example_animal_proxy_new_sync (connection, 0, NULL,
1819                                            "/Example/Animals/000", NULL, &error);
1820   g_assert_no_error (error);
1821   g_assert (animal1 != NULL);
1822   g_object_unref (connection);
1823 
1824   /* Get animal 2 ...  */
1825   connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
1826                                                        G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
1827                                                        NULL, /* GDBusAuthObserver */
1828                                                        NULL, /* cancellable */
1829                                                        &error);
1830   g_assert_no_error (error);
1831   g_assert (connection != NULL);
1832 
1833   animal2 = example_animal_proxy_new_sync (connection, 0, NULL,
1834                                            "/Example/Animals/000", NULL, &error);
1835   g_assert_no_error (error);
1836   g_assert (animal2 != NULL);
1837   g_object_unref (connection);
1838 
1839   /* Make animal sad via animal1  */
1840   example_animal_call_poke_sync (animal1, TRUE, FALSE, NULL, &error);
1841   g_assert_no_error (error);
1842 
1843   /* Poke server and make sure animal is updated */
1844   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal1),
1845                                   "org.freedesktop.DBus.Peer.Ping",
1846                                   NULL, G_DBUS_CALL_FLAGS_NONE, -1,
1847                                   NULL, &error);
1848   g_assert_no_error (error);
1849   g_assert (value != NULL);
1850   g_variant_unref (value);
1851 
1852   /* Give the proxies a chance to refresh in the defaul main loop */
1853   g_timeout_add (100, codegen_quit_mainloop_timeout, NULL);
1854   g_main_loop_run (loop);
1855 
1856   /* Assert animals are sad */
1857   g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Sad");
1858   g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Sad");
1859 
1860   /* Make animal happy via animal2  */
1861   example_animal_call_poke_sync (animal2, FALSE, TRUE, NULL, &error);
1862   g_assert_no_error (error);
1863 
1864   /* Some random unrelated call, just to get some test coverage */
1865   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal2),
1866                                   "org.freedesktop.DBus.Peer.GetMachineId",
1867                                   NULL, G_DBUS_CALL_FLAGS_NONE, -1,
1868                                   NULL, &error);
1869   g_assert_no_error (error);
1870   g_variant_get (value, "(&s)", &s);
1871   g_test_message ("Machine ID: %s", s);
1872   /* It's valid for machine-id inside containers to be empty, so we
1873    * need to test for that possibility
1874    */
1875   g_assert ((s == NULL || *s == '\0') || g_dbus_is_guid (s));
1876   g_variant_unref (value);
1877 
1878   /* Poke server and make sure animal is updated */
1879   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal2),
1880                                   "org.freedesktop.DBus.Peer.Ping",
1881                                   NULL, G_DBUS_CALL_FLAGS_NONE, -1,
1882                                   NULL, &error);
1883   g_assert_no_error (error);
1884   g_assert (value != NULL);
1885   g_variant_unref (value);
1886 
1887   /* Give the proxies a chance to refresh in the defaul main loop */
1888   g_timeout_add (1000, codegen_quit_mainloop_timeout, NULL);
1889   g_main_loop_run (loop);
1890 
1891   /* Assert animals are happy */
1892   g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Happy");
1893   g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Happy");
1894 
1895   /* This final call making the animal happy and sad will cause
1896    * the server to quit, when the server quits we dont get property
1897    * change notifications anyway because those are done from an idle handler
1898    */
1899   example_animal_call_poke_sync (animal2, TRUE, TRUE, NULL, &error);
1900   g_clear_error (&error);
1901 
1902   g_object_unref (animal1);
1903   g_object_unref (animal2);
1904   g_thread_join (service_thread);
1905 
1906   teardown_test_address ();
1907 
1908   g_main_loop_unref (loop);
1909   g_free (test_guid);
1910 }
1911 
1912 /* ---------------------------------------------------------------------------------------------------- */
1913 
1914 
1915 int
main(int argc,char * argv[])1916 main (int   argc,
1917       char *argv[])
1918 {
1919   gint ret;
1920   GDBusNodeInfo *introspection_data = NULL;
1921 
1922   g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1923 
1924   introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
1925   g_assert (introspection_data != NULL);
1926   test_interface_introspection_data = introspection_data->interfaces[0];
1927 
1928   g_test_add_func ("/gdbus/peer-to-peer", test_peer);
1929   g_test_add_func ("/gdbus/peer-to-peer/signals", test_peer_signals);
1930   g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing);
1931   g_test_add_func ("/gdbus/nonce-tcp", test_nonce_tcp);
1932 
1933   g_test_add_func ("/gdbus/tcp-anonymous", test_tcp_anonymous);
1934   g_test_add_func ("/gdbus/credentials", test_credentials);
1935   g_test_add_func ("/gdbus/codegen-peer-to-peer", codegen_test_peer);
1936 
1937   ret = g_test_run ();
1938 
1939   g_dbus_node_info_unref (introspection_data);
1940 
1941   return ret;
1942 }
1943