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