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