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