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