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