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