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