Bug 623815 – Don't check sender for GDBusProxy objects where name is not set
[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 <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
32 #include <gio/gunixsocketaddress.h>
33 #include <gio/gunixfdlist.h>
34
35 #include "gdbus-tests.h"
36
37
38 #ifdef G_OS_UNIX
39 static gboolean is_unix = TRUE;
40 #else
41 static gboolean is_unix = FALSE;
42 #endif
43
44 static gchar *test_guid = NULL;
45 static GMainLoop *service_loop = NULL;
46 static GDBusServer *server = NULL;
47 static GMainLoop *loop = NULL;
48
49 /* ---------------------------------------------------------------------------------------------------- */
50 /* Test that peer-to-peer connections work */
51 /* ---------------------------------------------------------------------------------------------------- */
52
53
54 typedef struct
55 {
56   gboolean accept_connection;
57   gint num_connection_attempts;
58   GPtrArray *current_connections;
59   guint num_method_calls;
60   gboolean signal_received;
61 } PeerData;
62
63 static const gchar *test_interface_introspection_xml =
64   "<node>"
65   "  <interface name='org.gtk.GDBus.PeerTestInterface'>"
66   "    <method name='HelloPeer'>"
67   "      <arg type='s' name='greeting' direction='in'/>"
68   "      <arg type='s' name='response' direction='out'/>"
69   "    </method>"
70   "    <method name='EmitSignal'/>"
71   "    <method name='EmitSignalWithNameSet'/>"
72   "    <method name='OpenFile'>"
73   "      <arg type='s' name='path' direction='in'/>"
74   "    </method>"
75   "    <signal name='PeerSignal'>"
76   "      <arg type='s' name='a_string'/>"
77   "    </signal>"
78   "    <property type='s' name='PeerProperty' access='read'/>"
79   "  </interface>"
80   "</node>";
81 static const GDBusInterfaceInfo *test_interface_introspection_data = NULL;
82
83 static void
84 test_interface_method_call (GDBusConnection       *connection,
85                             const gchar           *sender,
86                             const gchar           *object_path,
87                             const gchar           *interface_name,
88                             const gchar           *method_name,
89                             GVariant              *parameters,
90                             GDBusMethodInvocation *invocation,
91                             gpointer               user_data)
92 {
93   PeerData *data = user_data;
94
95   data->num_method_calls++;
96
97   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
98   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
99
100   if (g_strcmp0 (method_name, "HelloPeer") == 0)
101     {
102       const gchar *greeting;
103       gchar *response;
104
105       g_variant_get (parameters, "(&s)", &greeting);
106
107       response = g_strdup_printf ("You greeted me with '%s'.",
108                                   greeting);
109       g_dbus_method_invocation_return_value (invocation,
110                                              g_variant_new ("(s)", response));
111       g_free (response);
112     }
113   else if (g_strcmp0 (method_name, "EmitSignal") == 0)
114     {
115       GError *error;
116
117       error = NULL;
118       g_dbus_connection_emit_signal (connection,
119                                      NULL,
120                                      "/org/gtk/GDBus/PeerTestObject",
121                                      "org.gtk.GDBus.PeerTestInterface",
122                                      "PeerSignal",
123                                      NULL,
124                                      &error);
125       g_assert_no_error (error);
126       g_dbus_method_invocation_return_value (invocation, NULL);
127     }
128   else if (g_strcmp0 (method_name, "EmitSignalWithNameSet") == 0)
129     {
130       GError *error;
131       gboolean ret;
132       GDBusMessage *message;
133
134       message = g_dbus_message_new_signal ("/org/gtk/GDBus/PeerTestObject",
135                                            "org.gtk.GDBus.PeerTestInterface",
136                                            "PeerSignalWithNameSet");
137       g_dbus_message_set_sender (message, ":1.42");
138
139       error = NULL;
140       ret = g_dbus_connection_send_message (connection, message, NULL, &error);
141       g_assert_no_error (error);
142       g_assert (ret);
143       g_object_unref (message);
144
145       g_dbus_method_invocation_return_value (invocation, NULL);
146     }
147   else if (g_strcmp0 (method_name, "OpenFile") == 0)
148     {
149 #ifdef G_OS_UNIX
150       const gchar *path;
151       GDBusMessage *reply;
152       GError *error;
153       gint fd;
154       GUnixFDList *fd_list;
155
156       g_variant_get (parameters, "(&s)", &path);
157
158       fd_list = g_unix_fd_list_new ();
159
160       error = NULL;
161
162       fd = open (path, O_RDONLY);
163       g_unix_fd_list_append (fd_list, fd, &error);
164       g_assert_no_error (error);
165       close (fd);
166
167       reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
168       g_dbus_message_set_unix_fd_list (reply, fd_list);
169       g_object_unref (invocation);
170
171       error = NULL;
172       g_dbus_connection_send_message (connection,
173                                       reply,
174                                       NULL, /* out_serial */
175                                       &error);
176       g_assert_no_error (error);
177       g_object_unref (reply);
178 #else
179       g_dbus_method_invocation_return_dbus_error (invocation,
180                                                   "org.gtk.GDBus.NotOnUnix",
181                                                   "Your OS does not support file descriptor passing");
182 #endif
183     }
184   else
185     {
186       g_assert_not_reached ();
187     }
188 }
189
190 static GVariant *
191 test_interface_get_property (GDBusConnection  *connection,
192                              const gchar      *sender,
193                              const gchar      *object_path,
194                              const gchar      *interface_name,
195                              const gchar      *property_name,
196                              GError          **error,
197                              gpointer          user_data)
198 {
199   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
200   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
201   g_assert_cmpstr (property_name, ==, "PeerProperty");
202
203   return g_variant_new_string ("ThePropertyValue");
204 }
205
206
207 static const GDBusInterfaceVTable test_interface_vtable =
208 {
209   test_interface_method_call,
210   test_interface_get_property,
211   NULL  /* set_property */
212 };
213
214 static void
215 on_proxy_signal_received (GDBusProxy *proxy,
216                           gchar      *sender_name,
217                           gchar      *signal_name,
218                           GVariant   *parameters,
219                           gpointer    user_data)
220 {
221   PeerData *data = user_data;
222
223   data->signal_received = TRUE;
224
225   g_assert (sender_name == NULL);
226   g_assert_cmpstr (signal_name, ==, "PeerSignal");
227   g_main_loop_quit (loop);
228 }
229
230 static void
231 on_proxy_signal_received_with_name_set (GDBusProxy *proxy,
232                                         gchar      *sender_name,
233                                         gchar      *signal_name,
234                                         GVariant   *parameters,
235                                         gpointer    user_data)
236 {
237   PeerData *data = user_data;
238
239   data->signal_received = TRUE;
240
241   g_assert_cmpstr (sender_name, ==, ":1.42");
242   g_assert_cmpstr (signal_name, ==, "PeerSignalWithNameSet");
243   g_main_loop_quit (loop);
244 }
245
246 /* ---------------------------------------------------------------------------------------------------- */
247
248 static gboolean
249 on_authorize_authenticated_peer (GDBusAuthObserver *observer,
250                                  GIOStream         *stream,
251                                  GCredentials      *credentials,
252                                  gpointer           user_data)
253 {
254   PeerData *data = user_data;
255   gboolean authorized;
256
257   data->num_connection_attempts++;
258
259   authorized = TRUE;
260   if (!data->accept_connection)
261     {
262       authorized = FALSE;
263       g_main_loop_quit (loop);
264     }
265
266   return authorized;
267 }
268
269 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
270 static void
271 on_new_connection (GDBusServer *server,
272                    GDBusConnection *connection,
273                    gpointer user_data)
274 {
275   PeerData *data = user_data;
276   GError *error;
277   guint reg_id;
278
279   //g_print ("Client connected.\n"
280   //         "Negotiated capabilities: unix-fd-passing=%d\n",
281   //         g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
282
283   g_ptr_array_add (data->current_connections, g_object_ref (connection));
284
285   /* export object on the newly established connection */
286   error = NULL;
287   reg_id = g_dbus_connection_register_object (connection,
288                                               "/org/gtk/GDBus/PeerTestObject",
289                                               test_interface_introspection_data,
290                                               &test_interface_vtable,
291                                               data,
292                                               NULL, /* GDestroyNotify for data */
293                                               &error);
294   g_assert_no_error (error);
295   g_assert (reg_id > 0);
296
297   g_main_loop_quit (loop);
298 }
299
300 static gpointer
301 service_thread_func (gpointer user_data)
302 {
303   PeerData *data = user_data;
304   GMainContext *service_context;
305   GDBusAuthObserver *observer;
306   GError *error;
307
308   service_context = g_main_context_new ();
309   g_main_context_push_thread_default (service_context);
310
311   error = NULL;
312   observer = g_dbus_auth_observer_new ();
313   server = g_dbus_server_new_sync (is_unix ? "unix:tmpdir=/tmp/gdbus-test-" : "nonce-tcp:",
314                                    G_DBUS_SERVER_FLAGS_NONE,
315                                    test_guid,
316                                    observer,
317                                    NULL, /* cancellable */
318                                    &error);
319   g_assert_no_error (error);
320
321   g_signal_connect (server,
322                     "new-connection",
323                     G_CALLBACK (on_new_connection),
324                     data);
325   g_signal_connect (observer,
326                     "authorize-authenticated-peer",
327                     G_CALLBACK (on_authorize_authenticated_peer),
328                     data);
329   g_object_unref (observer);
330
331   g_dbus_server_start (server);
332
333   service_loop = g_main_loop_new (service_context, FALSE);
334   g_main_loop_run (service_loop);
335
336   g_main_context_pop_thread_default (service_context);
337
338   g_main_loop_unref (service_loop);
339   g_main_context_unref (service_context);
340
341   /* test code specifically unrefs the server - see below */
342   g_assert (server == NULL);
343
344   return NULL;
345 }
346
347 #if 0
348 static gboolean
349 on_incoming_connection (GSocketService     *service,
350                         GSocketConnection  *socket_connection,
351                         GObject            *source_object,
352                         gpointer           user_data)
353 {
354   PeerData *data = user_data;
355
356   if (data->accept_connection)
357     {
358       GError *error;
359       guint reg_id;
360       GDBusConnection *connection;
361
362       error = NULL;
363       connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
364                                                test_guid,
365                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
366                                                NULL, /* cancellable */
367                                                &error);
368       g_assert_no_error (error);
369
370       g_ptr_array_add (data->current_connections, connection);
371
372       /* export object on the newly established connection */
373       error = NULL;
374       reg_id = g_dbus_connection_register_object (connection,
375                                                   "/org/gtk/GDBus/PeerTestObject",
376                                                   &test_interface_introspection_data,
377                                                   &test_interface_vtable,
378                                                   data,
379                                                   NULL, /* GDestroyNotify for data */
380                                                   &error);
381       g_assert_no_error (error);
382       g_assert (reg_id > 0);
383
384     }
385   else
386     {
387       /* don't do anything */
388     }
389
390   data->num_connection_attempts++;
391
392   g_main_loop_quit (loop);
393
394   /* stops other signal handlers from being invoked */
395   return TRUE;
396 }
397
398 static gpointer
399 service_thread_func (gpointer data)
400 {
401   GMainContext *service_context;
402   gchar *socket_path;
403   GSocketAddress *address;
404   GError *error;
405
406   service_context = g_main_context_new ();
407   g_main_context_push_thread_default (service_context);
408
409   socket_path = g_strdup_printf ("/tmp/gdbus-test-pid-%d", getpid ());
410   address = g_unix_socket_address_new (socket_path);
411
412   service = g_socket_service_new ();
413   error = NULL;
414   g_socket_listener_add_address (G_SOCKET_LISTENER (service),
415                                  address,
416                                  G_SOCKET_TYPE_STREAM,
417                                  G_SOCKET_PROTOCOL_DEFAULT,
418                                  NULL, /* source_object */
419                                  NULL, /* effective_address */
420                                  &error);
421   g_assert_no_error (error);
422   g_signal_connect (service,
423                     "incoming",
424                     G_CALLBACK (on_incoming_connection),
425                     data);
426   g_socket_service_start (service);
427
428   service_loop = g_main_loop_new (service_context, FALSE);
429   g_main_loop_run (service_loop);
430
431   g_main_context_pop_thread_default (service_context);
432
433   g_main_loop_unref (service_loop);
434   g_main_context_unref (service_context);
435
436   g_object_unref (address);
437   g_free (socket_path);
438   return NULL;
439 }
440 #endif
441
442 /* ---------------------------------------------------------------------------------------------------- */
443
444 #if 0
445 static gboolean
446 check_connection (gpointer user_data)
447 {
448   PeerData *data = user_data;
449   guint n;
450
451   for (n = 0; n < data->current_connections->len; n++)
452     {
453       GDBusConnection *c;
454       GIOStream *stream;
455
456       c = G_DBUS_CONNECTION (data->current_connections->pdata[n]);
457       stream = g_dbus_connection_get_stream (c);
458
459       g_debug ("In check_connection for %d: connection %p, stream %p", n, c, stream);
460       g_debug ("closed = %d", g_io_stream_is_closed (stream));
461
462       GSocket *socket;
463       socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
464       g_debug ("socket_closed = %d", g_socket_is_closed (socket));
465       g_debug ("socket_condition_check = %d", g_socket_condition_check (socket, G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP));
466
467       gchar buf[128];
468       GError *error;
469       gssize num_read;
470       error = NULL;
471       num_read = g_input_stream_read (g_io_stream_get_input_stream (stream),
472                                       buf,
473                                       128,
474                                       NULL,
475                                       &error);
476       if (num_read < 0)
477         {
478           g_debug ("error: %s", error->message);
479           g_error_free (error);
480         }
481       else
482         {
483           g_debug ("no error, read %d bytes", (gint) num_read);
484         }
485     }
486
487   return FALSE;
488 }
489
490 static gboolean
491 on_do_disconnect_in_idle (gpointer data)
492 {
493   GDBusConnection *c = G_DBUS_CONNECTION (data);
494   g_debug ("GDC %p has ref_count %d", c, G_OBJECT (c)->ref_count);
495   g_dbus_connection_disconnect (c);
496   g_object_unref (c);
497   return FALSE;
498 }
499 #endif
500
501 static void
502 test_peer (void)
503 {
504   GDBusConnection *c;
505   GDBusConnection *c2;
506   GDBusProxy *proxy;
507   GError *error;
508   PeerData data;
509   GVariant *value;
510   GVariant *result;
511   const gchar *s;
512   GThread *service_thread;
513   gulong signal_handler_id;
514
515   memset (&data, '\0', sizeof (PeerData));
516   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
517
518   /* first try to connect when there is no server */
519   error = NULL;
520   c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" :
521                                               /* NOTE: Even if something is listening on port 12345 the connection
522                                                * will fail because the nonce file doesn't exist */
523                                               "nonce-tcp:host=localhost,port=12345,noncefile=this-does-not-exist-gdbus",
524                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
525                                               NULL, /* GDBusAuthObserver */
526                                               NULL, /* cancellable */
527                                               &error);
528   _g_assert_error_domain (error, G_IO_ERROR);
529   g_assert (!g_dbus_error_is_remote_error (error));
530   g_clear_error (&error);
531   g_assert (c == NULL);
532
533   /* bring up a server - we run the server in a different thread to avoid deadlocks */
534   error = NULL;
535   service_thread = g_thread_create (service_thread_func,
536                                     &data,
537                                     TRUE,
538                                     &error);
539   while (service_loop == NULL)
540     g_thread_yield ();
541   g_assert (server != NULL);
542
543   /* bring up a connection and accept it */
544   data.accept_connection = TRUE;
545   error = NULL;
546   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
547                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
548                                               NULL, /* GDBusAuthObserver */
549                                               NULL, /* cancellable */
550                                               &error);
551   g_assert_no_error (error);
552   g_assert (c != NULL);
553   while (data.current_connections->len < 1)
554     g_main_loop_run (loop);
555   g_assert_cmpint (data.current_connections->len, ==, 1);
556   g_assert_cmpint (data.num_connection_attempts, ==, 1);
557   g_assert (g_dbus_connection_get_unique_name (c) == NULL);
558   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
559
560   /* check that we create a proxy, read properties, receive signals and invoke
561    * the HelloPeer() method. Since the server runs in another thread it's fine
562    * to use synchronous blocking API here.
563    */
564   error = NULL;
565   proxy = g_dbus_proxy_new_sync (c,
566                                  G_DBUS_PROXY_FLAGS_NONE,
567                                  NULL,
568                                  NULL, /* bus_name */
569                                  "/org/gtk/GDBus/PeerTestObject",
570                                  "org.gtk.GDBus.PeerTestInterface",
571                                  NULL, /* GCancellable */
572                                  &error);
573   g_assert_no_error (error);
574   g_assert (proxy != NULL);
575   error = NULL;
576   value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
577   g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
578
579   /* try invoking a method */
580   error = NULL;
581   result = g_dbus_proxy_call_sync (proxy,
582                                    "HelloPeer",
583                                    g_variant_new ("(s)", "Hey Peer!"),
584                                    G_DBUS_CALL_FLAGS_NONE,
585                                    -1,
586                                    NULL,  /* GCancellable */
587                                    &error);
588   g_assert_no_error (error);
589   g_variant_get (result, "(&s)", &s);
590   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Peer!'.");
591   g_variant_unref (result);
592   g_assert_cmpint (data.num_method_calls, ==, 1);
593
594   /* make the other peer emit a signal - catch it */
595   signal_handler_id = g_signal_connect (proxy,
596                                         "g-signal",
597                                         G_CALLBACK (on_proxy_signal_received),
598                                         &data);
599   g_assert (!data.signal_received);
600   g_dbus_proxy_call (proxy,
601                      "EmitSignal",
602                      NULL,  /* no arguments */
603                      G_DBUS_CALL_FLAGS_NONE,
604                      -1,
605                      NULL,  /* GCancellable */
606                      NULL,  /* GAsyncReadyCallback - we don't care about the result */
607                      NULL); /* user_data */
608   g_main_loop_run (loop);
609   g_assert (data.signal_received);
610   g_assert_cmpint (data.num_method_calls, ==, 2);
611   g_signal_handler_disconnect (proxy, signal_handler_id);
612
613   /* Also ensure that messages with the sender header-field set gets
614    * delivered to the proxy - note that this doesn't really make sense
615    * e.g. names are meaning-less in a peer-to-peer case... but we
616    * support it because it makes sense in certain bridging
617    * applications - see e.g. #623815.
618    */
619   signal_handler_id = g_signal_connect (proxy,
620                                         "g-signal",
621                                         G_CALLBACK (on_proxy_signal_received_with_name_set),
622                                         &data);
623   data.signal_received = FALSE;
624   g_dbus_proxy_call (proxy,
625                      "EmitSignalWithNameSet",
626                      NULL,  /* no arguments */
627                      G_DBUS_CALL_FLAGS_NONE,
628                      -1,
629                      NULL,  /* GCancellable */
630                      NULL,  /* GAsyncReadyCallback - we don't care about the result */
631                      NULL); /* user_data */
632   g_main_loop_run (loop);
633   g_assert (data.signal_received);
634   g_assert_cmpint (data.num_method_calls, ==, 3);
635   g_signal_handler_disconnect (proxy, signal_handler_id);
636
637   /* check for UNIX fd passing */
638 #ifdef G_OS_UNIX
639   {
640     GDBusMessage *method_call_message;
641     GDBusMessage *method_reply_message;
642     GUnixFDList *fd_list;
643     gint fd;
644     gchar buf[1024];
645     gssize len;
646     gchar *buf2;
647     gsize len2;
648
649     method_call_message = g_dbus_message_new_method_call (NULL, /* name */
650                                                           "/org/gtk/GDBus/PeerTestObject",
651                                                           "org.gtk.GDBus.PeerTestInterface",
652                                                           "OpenFile");
653     g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", "/etc/hosts"));
654     error = NULL;
655     method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
656                                                                            method_call_message,
657                                                                            -1,
658                                                                            NULL, /* out_serial */
659                                                                            NULL, /* cancellable */
660                                                                            &error);
661     g_assert_no_error (error);
662     g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
663     fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
664     g_assert (fd_list != NULL);
665     g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
666     error = NULL;
667     fd = g_unix_fd_list_get (fd_list, 0, &error);
668     g_assert_no_error (error);
669     g_object_unref (method_call_message);
670     g_object_unref (method_reply_message);
671
672     memset (buf, '\0', sizeof (buf));
673     len = read (fd, buf, sizeof (buf) - 1);
674     close (fd);
675
676     error = NULL;
677     g_file_get_contents ("/etc/hosts",
678                          &buf2,
679                          &len2,
680                          &error);
681     g_assert_no_error (error);
682     if (len2 > sizeof (buf))
683       buf2[sizeof (buf)] = '\0';
684     g_assert_cmpstr (buf, ==, buf2);
685     g_free (buf2);
686   }
687 #else
688   error = NULL;
689   result = g_dbus_proxy_call_sync (proxy,
690                                    "OpenFile",
691                                    g_variant_new ("(s)", "boo"),
692                                    G_DBUS_CALL_FLAGS_NONE,
693                                    -1,
694                                    NULL,  /* GCancellable */
695                                    &error);
696   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
697   g_assert (result == NULL);
698   g_error_free (error);
699 #endif /* G_OS_UNIX */
700
701
702   /* bring up a connection - don't accept it - this should fail
703    */
704   data.accept_connection = FALSE;
705   error = NULL;
706   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
707                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
708                                                NULL, /* GDBusAuthObserver */
709                                                NULL, /* cancellable */
710                                                &error);
711   _g_assert_error_domain (error, G_IO_ERROR);
712   g_assert (c2 == NULL);
713
714 #if 0
715   /* TODO: THIS TEST DOESN'T WORK YET */
716
717   /* bring up a connection - accept it.. then disconnect from the client side - check
718    * that the server side gets the disconnect signal.
719    */
720   error = NULL;
721   data.accept_connection = TRUE;
722   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
723                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
724                                                NULL, /* GDBusAuthObserver */
725                                                NULL, /* cancellable */
726                                                &error);
727   g_assert_no_error (error);
728   g_assert (c2 != NULL);
729   g_assert (!g_dbus_connection_get_is_disconnected (c2));
730   while (data.num_connection_attempts < 3)
731     g_main_loop_run (loop);
732   g_assert_cmpint (data.current_connections->len, ==, 2);
733   g_assert_cmpint (data.num_connection_attempts, ==, 3);
734   g_assert (!g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
735   g_idle_add (on_do_disconnect_in_idle, c2);
736   g_debug ("==================================================");
737   g_debug ("==================================================");
738   g_debug ("==================================================");
739   g_debug ("waiting for disconnect on connection %p, stream %p",
740            data.current_connections->pdata[1],
741            g_dbus_connection_get_stream (data.current_connections->pdata[1]));
742
743   g_timeout_add (2000, check_connection, &data);
744   //_g_assert_signal_received (G_DBUS_CONNECTION (data.current_connections->pdata[1]), "closed");
745   g_main_loop_run (loop);
746   g_assert (g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
747   g_ptr_array_set_size (data.current_connections, 1); /* remove disconnected connection object */
748 #endif
749
750   /* unref the server and stop listening for new connections
751    *
752    * This won't bring down the established connections - check that c is still connected
753    * by invoking a method
754    */
755   //g_socket_service_stop (service);
756   //g_object_unref (service);
757   g_dbus_server_stop (server);
758   g_object_unref (server);
759   server = NULL;
760
761   error = NULL;
762   result = g_dbus_proxy_call_sync (proxy,
763                                    "HelloPeer",
764                                    g_variant_new ("(s)", "Hey Again Peer!"),
765                                    G_DBUS_CALL_FLAGS_NONE,
766                                    -1,
767                                    NULL,  /* GCancellable */
768                                    &error);
769   g_assert_no_error (error);
770   g_variant_get (result, "(&s)", &s);
771   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
772   g_variant_unref (result);
773   g_assert_cmpint (data.num_method_calls, ==, 5);
774
775 #if 0
776   /* TODO: THIS TEST DOESN'T WORK YET */
777
778   /* now disconnect from the server side - check that the client side gets the signal */
779   g_assert_cmpint (data.current_connections->len, ==, 1);
780   g_assert (G_DBUS_CONNECTION (data.current_connections->pdata[0]) != c);
781   g_dbus_connection_disconnect (G_DBUS_CONNECTION (data.current_connections->pdata[0]));
782   if (!g_dbus_connection_get_is_disconnected (c))
783     _g_assert_signal_received (c, "closed");
784   g_assert (g_dbus_connection_get_is_disconnected (c));
785 #endif
786
787   g_object_unref (c);
788   g_ptr_array_unref (data.current_connections);
789   g_object_unref (proxy);
790
791   g_main_loop_quit (service_loop);
792   g_thread_join (service_thread);
793 }
794
795 /* ---------------------------------------------------------------------------------------------------- */
796
797 typedef struct
798 {
799   GDBusServer *server;
800   GMainContext *context;
801   GMainLoop *loop;
802
803   GList *connections;
804 } DmpData;
805
806 static void
807 dmp_data_free (DmpData *data)
808 {
809   g_main_loop_unref (data->loop);
810   g_main_context_unref (data->context);
811   g_object_unref (data->server);
812   g_list_foreach (data->connections, (GFunc) g_object_unref, NULL);
813   g_list_free (data->connections);
814   g_free (data);
815 }
816
817 static void
818 dmp_on_method_call (GDBusConnection       *connection,
819                     const gchar           *sender,
820                     const gchar           *object_path,
821                     const gchar           *interface_name,
822                     const gchar           *method_name,
823                     GVariant              *parameters,
824                     GDBusMethodInvocation *invocation,
825                     gpointer               user_data)
826 {
827   //DmpData *data = user_data;
828   gint32 first;
829   gint32 second;
830   g_variant_get (parameters,
831                  "(ii)",
832                  &first,
833                  &second);
834   g_dbus_method_invocation_return_value (invocation,
835                                          g_variant_new ("(i)", first + second));
836 }
837
838 static const GDBusInterfaceVTable dmp_interface_vtable =
839 {
840   dmp_on_method_call,
841   NULL,  /* get_property */
842   NULL   /* set_property */
843 };
844
845
846 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
847 static void
848 dmp_on_new_connection (GDBusServer     *server,
849                        GDBusConnection *connection,
850                        gpointer         user_data)
851 {
852   DmpData *data = user_data;
853   GDBusNodeInfo *node;
854   GError *error;
855
856   /* accept the connection */
857   data->connections = g_list_prepend (data->connections, g_object_ref (connection));
858
859   error = NULL;
860   node = g_dbus_node_info_new_for_xml ("<node>"
861                                        "  <interface name='org.gtk.GDBus.DmpInterface'>"
862                                        "    <method name='AddPair'>"
863                                        "      <arg type='i' name='first' direction='in'/>"
864                                        "      <arg type='i' name='second' direction='in'/>"
865                                        "      <arg type='i' name='sum' direction='out'/>"
866                                        "    </method>"
867                                        "  </interface>"
868                                        "</node>",
869                                        &error);
870   g_assert_no_error (error);
871
872   /* sleep 100ms before exporting an object - this is to test that
873    * G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING really works
874    * (GDBusServer uses this feature).
875    */
876   usleep (100 * 1000);
877
878   /* export an object */
879   error = NULL;
880   g_dbus_connection_register_object (connection,
881                                      "/dmp/test",
882                                      node->interfaces[0],
883                                      &dmp_interface_vtable,
884                                      data,
885                                      NULL,
886                                      &error);
887   g_dbus_node_info_unref (node);
888 }
889
890 static gpointer
891 dmp_thread_func (gpointer user_data)
892 {
893   DmpData *data = user_data;
894   GError *error;
895   gchar *guid;
896
897   data->context = g_main_context_new ();
898   g_main_context_push_thread_default (data->context);
899
900   error = NULL;
901   guid = g_dbus_generate_guid ();
902   data->server = g_dbus_server_new_sync ("unix:tmpdir=/tmp/gdbus-test-",
903                                          G_DBUS_SERVER_FLAGS_NONE,
904                                          guid,
905                                          NULL, /* GDBusAuthObserver */
906                                          NULL, /* GCancellable */
907                                          &error);
908   g_assert_no_error (error);
909   g_signal_connect (data->server,
910                     "new-connection",
911                     G_CALLBACK (dmp_on_new_connection),
912                     data);
913
914   g_dbus_server_start (data->server);
915
916   data->loop = g_main_loop_new (data->context, FALSE);
917   g_main_loop_run (data->loop);
918
919   g_main_context_pop_thread_default (data->context);
920
921   g_free (guid);
922   return NULL;
923 }
924
925 static void
926 delayed_message_processing (void)
927 {
928   GError *error;
929   DmpData *data;
930   GThread *service_thread;
931   guint n;
932
933   data = g_new0 (DmpData, 1);
934
935   error = NULL;
936   service_thread = g_thread_create (dmp_thread_func,
937                                     data,
938                                     TRUE,
939                                     &error);
940   while (data->server == NULL || !g_dbus_server_is_active (data->server))
941     g_thread_yield ();
942
943   for (n = 0; n < 5; n++)
944     {
945       GDBusConnection *c;
946       GVariant *res;
947       gint32 val;
948
949       error = NULL;
950       c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (data->server),
951                                                   G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
952                                                   NULL, /* GDBusAuthObserver */
953                                                   NULL, /* GCancellable */
954                                                   &error);
955       g_assert_no_error (error);
956
957       error = NULL;
958       res = g_dbus_connection_call_sync (c,
959                                          NULL,    /* bus name */
960                                          "/dmp/test",
961                                          "org.gtk.GDBus.DmpInterface",
962                                          "AddPair",
963                                          g_variant_new ("(ii)", 2, n),
964                                          G_VARIANT_TYPE ("(i)"),
965                                          G_DBUS_CALL_FLAGS_NONE,
966                                          -1, /* timeout_msec */
967                                          NULL, /* GCancellable */
968                                          &error);
969       g_assert_no_error (error);
970       g_variant_get (res, "(i)", &val);
971       g_assert_cmpint (val, ==, 2 + n);
972       g_variant_unref (res);
973       g_object_unref (c);
974   }
975
976   g_main_loop_quit (data->loop);
977   g_thread_join (service_thread);
978   dmp_data_free (data);
979 }
980
981 /* ---------------------------------------------------------------------------------------------------- */
982
983 int
984 main (int   argc,
985       char *argv[])
986 {
987   gint ret;
988   GDBusNodeInfo *introspection_data = NULL;
989
990   g_type_init ();
991   g_thread_init (NULL);
992   g_test_init (&argc, &argv, NULL);
993
994   introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
995   g_assert (introspection_data != NULL);
996   test_interface_introspection_data = introspection_data->interfaces[0];
997
998   test_guid = g_dbus_generate_guid ();
999
1000   /* all the tests rely on a shared main loop */
1001   loop = g_main_loop_new (NULL, FALSE);
1002
1003   g_test_add_func ("/gdbus/peer-to-peer", test_peer);
1004   g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing);
1005
1006   ret = g_test_run();
1007
1008   g_main_loop_unref (loop);
1009   g_free (test_guid);
1010   g_dbus_node_info_unref (introspection_data);
1011
1012   return ret;
1013 }