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