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