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