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