Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : *
3 : : * Copyright (C) 2008-2010 Red Hat, Inc.
4 : : * Copyright (C) 2021 Frederic Martinsons
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General
19 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 : : *
21 : : * Author: David Zeuthen <davidz@redhat.com>
22 : : * Author: Frederic Martinsons <frederic.martinsons@gmail.com>
23 : : */
24 : :
25 : : #include <gio/gio.h>
26 : : #include <unistd.h>
27 : :
28 : : #include "gdbusprivate.h"
29 : : #include "gdbus-tests.h"
30 : :
31 : : /* ---------------------------------------------------------------------------------------------------- */
32 : : /* Test that g_bus_own_name() works correctly */
33 : : /* ---------------------------------------------------------------------------------------------------- */
34 : :
35 : : typedef struct
36 : : {
37 : : gboolean expect_null_connection;
38 : : guint num_bus_acquired;
39 : : guint num_acquired;
40 : : guint num_lost;
41 : : guint num_free_func;
42 : : GMainContext *main_context; /* (unowned) */
43 : : } OwnNameData;
44 : :
45 : : static void
46 : 21 : own_name_data_free_func (OwnNameData *data)
47 : : {
48 : 21 : data->num_free_func++;
49 : 21 : g_main_context_wakeup (data->main_context);
50 : 21 : }
51 : :
52 : : static void
53 : 4 : bus_acquired_handler (GDBusConnection *connection,
54 : : const gchar *name,
55 : : gpointer user_data)
56 : : {
57 : 4 : OwnNameData *data = user_data;
58 : 4 : g_dbus_connection_set_exit_on_close (connection, FALSE);
59 : 4 : data->num_bus_acquired += 1;
60 : 4 : g_main_context_wakeup (data->main_context);
61 : 4 : }
62 : :
63 : : static void
64 : 5 : name_acquired_handler (GDBusConnection *connection,
65 : : const gchar *name,
66 : : gpointer user_data)
67 : : {
68 : 5 : OwnNameData *data = user_data;
69 : 5 : data->num_acquired += 1;
70 : 5 : g_main_context_wakeup (data->main_context);
71 : 5 : }
72 : :
73 : : static void
74 : 7 : name_lost_handler (GDBusConnection *connection,
75 : : const gchar *name,
76 : : gpointer user_data)
77 : : {
78 : 7 : OwnNameData *data = user_data;
79 : 7 : if (data->expect_null_connection)
80 : : {
81 : 2 : g_assert (connection == NULL);
82 : : }
83 : : else
84 : : {
85 : 5 : g_assert (connection != NULL);
86 : 5 : g_dbus_connection_set_exit_on_close (connection, FALSE);
87 : : }
88 : 7 : data->num_lost += 1;
89 : 7 : g_main_context_wakeup (data->main_context);
90 : 7 : }
91 : :
92 : : static void
93 : 1 : test_bus_own_name (void)
94 : : {
95 : : guint id;
96 : : guint id2;
97 : : OwnNameData data;
98 : : OwnNameData data2;
99 : : const gchar *name;
100 : : GDBusConnection *c;
101 : : GError *error;
102 : : gboolean name_has_owner_reply;
103 : : GDBusConnection *c2;
104 : : GVariant *result;
105 : 1 : GMainContext *main_context = NULL; /* use the global default for now */
106 : :
107 : 1 : error = NULL;
108 : 1 : name = "org.gtk.GDBus.Name1";
109 : :
110 : : /*
111 : : * First check that name_lost_handler() is invoked if there is no bus.
112 : : *
113 : : * Also make sure name_lost_handler() isn't invoked when unowning the name.
114 : : */
115 : 1 : data.num_bus_acquired = 0;
116 : 1 : data.num_free_func = 0;
117 : 1 : data.num_acquired = 0;
118 : 1 : data.num_lost = 0;
119 : 1 : data.expect_null_connection = TRUE;
120 : 1 : data.main_context = main_context;
121 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
122 : : name,
123 : : G_BUS_NAME_OWNER_FLAGS_NONE,
124 : : bus_acquired_handler,
125 : : name_acquired_handler,
126 : : name_lost_handler,
127 : : &data,
128 : : (GDestroyNotify) own_name_data_free_func);
129 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
130 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
131 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
132 : :
133 : 2 : while (data.num_lost < 1)
134 : 1 : g_main_context_iteration (main_context, TRUE);
135 : :
136 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
137 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
138 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
139 : 1 : g_bus_unown_name (id);
140 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
141 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
142 : 1 : g_assert_cmpint (data.num_free_func, ==, 1);
143 : :
144 : : /*
145 : : * Bring up a bus, then own a name and check bus_acquired_handler() then name_acquired_handler() is invoked.
146 : : */
147 : 1 : session_bus_up ();
148 : 1 : data.num_bus_acquired = 0;
149 : 1 : data.num_acquired = 0;
150 : 1 : data.num_lost = 0;
151 : 1 : data.expect_null_connection = FALSE;
152 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
153 : : name,
154 : : G_BUS_NAME_OWNER_FLAGS_NONE,
155 : : bus_acquired_handler,
156 : : name_acquired_handler,
157 : : name_lost_handler,
158 : : &data,
159 : : (GDestroyNotify) own_name_data_free_func);
160 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
161 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
162 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
163 : :
164 : 3 : while (data.num_bus_acquired < 1)
165 : 2 : g_main_context_iteration (main_context, TRUE);
166 : :
167 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
168 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
169 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
170 : :
171 : 3 : while (data.num_acquired < 1)
172 : 2 : g_main_context_iteration (main_context, TRUE);
173 : :
174 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
175 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
176 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
177 : :
178 : : /*
179 : : * Check that the name was actually acquired.
180 : : */
181 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
182 : 1 : g_assert (c != NULL);
183 : 1 : g_assert (!g_dbus_connection_is_closed (c));
184 : 1 : result = g_dbus_connection_call_sync (c,
185 : : DBUS_SERVICE_DBUS,
186 : : DBUS_PATH_DBUS,
187 : : DBUS_INTERFACE_DBUS,
188 : : "NameHasOwner", /* method name */
189 : : g_variant_new ("(s)", name),
190 : : G_VARIANT_TYPE ("(b)"),
191 : : G_DBUS_CALL_FLAGS_NONE,
192 : : -1,
193 : : NULL,
194 : : &error);
195 : 1 : g_assert_no_error (error);
196 : 1 : g_assert (result != NULL);
197 : 1 : g_variant_get (result, "(b)", &name_has_owner_reply);
198 : 1 : g_assert (name_has_owner_reply);
199 : 1 : g_variant_unref (result);
200 : :
201 : : /*
202 : : * Stop owning the name - this should invoke our free func
203 : : */
204 : 1 : g_bus_unown_name (id);
205 : 3 : while (data.num_free_func < 2)
206 : 2 : g_main_context_iteration (main_context, TRUE);
207 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
208 : :
209 : : /*
210 : : * Check that the name was actually released.
211 : : */
212 : 1 : result = g_dbus_connection_call_sync (c,
213 : : DBUS_SERVICE_DBUS,
214 : : DBUS_PATH_DBUS,
215 : : DBUS_INTERFACE_DBUS,
216 : : "NameHasOwner", /* method name */
217 : : g_variant_new ("(s)", name),
218 : : G_VARIANT_TYPE ("(b)"),
219 : : G_DBUS_CALL_FLAGS_NONE,
220 : : -1,
221 : : NULL,
222 : : &error);
223 : 1 : g_assert_no_error (error);
224 : 1 : g_assert (result != NULL);
225 : 1 : g_variant_get (result, "(b)", &name_has_owner_reply);
226 : 1 : g_assert (!name_has_owner_reply);
227 : 1 : g_variant_unref (result);
228 : :
229 : : /* Now try owning the name and then immediately decide to unown the name */
230 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
231 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
232 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
233 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
234 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
235 : : name,
236 : : G_BUS_NAME_OWNER_FLAGS_NONE,
237 : : bus_acquired_handler,
238 : : name_acquired_handler,
239 : : name_lost_handler,
240 : : &data,
241 : : (GDestroyNotify) own_name_data_free_func);
242 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
243 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
244 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
245 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
246 : 1 : g_bus_unown_name (id);
247 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
248 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
249 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
250 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
251 : :
252 : : /* the GDestroyNotify is called in idle because the bus is acquired in idle */
253 : 3 : while (data.num_free_func < 3)
254 : 2 : g_main_context_iteration (main_context, TRUE);
255 : :
256 : 1 : g_assert_cmpint (data.num_free_func, ==, 3);
257 : :
258 : : /*
259 : : * Own the name again.
260 : : */
261 : 1 : data.num_bus_acquired = 0;
262 : 1 : data.num_acquired = 0;
263 : 1 : data.num_lost = 0;
264 : 1 : data.expect_null_connection = FALSE;
265 : 1 : id = g_bus_own_name_with_closures (G_BUS_TYPE_SESSION,
266 : : name,
267 : : G_BUS_NAME_OWNER_FLAGS_NONE,
268 : : g_cclosure_new (G_CALLBACK (bus_acquired_handler),
269 : : &data,
270 : : NULL),
271 : : g_cclosure_new (G_CALLBACK (name_acquired_handler),
272 : : &data,
273 : : NULL),
274 : : g_cclosure_new (G_CALLBACK (name_lost_handler),
275 : : &data,
276 : : (GClosureNotify) own_name_data_free_func));
277 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
278 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
279 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
280 : :
281 : 3 : while (data.num_bus_acquired < 1)
282 : 2 : g_main_context_iteration (main_context, TRUE);
283 : :
284 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
285 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
286 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
287 : :
288 : 3 : while (data.num_acquired < 1)
289 : 2 : g_main_context_iteration (main_context, TRUE);
290 : :
291 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
292 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
293 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
294 : :
295 : : /*
296 : : * Try owning the name with another object on the same connection - this should
297 : : * fail because we already own the name.
298 : : */
299 : 1 : data2.num_free_func = 0;
300 : 1 : data2.num_bus_acquired = 0;
301 : 1 : data2.num_acquired = 0;
302 : 1 : data2.num_lost = 0;
303 : 1 : data2.expect_null_connection = FALSE;
304 : 1 : data2.main_context = main_context;
305 : 1 : id2 = g_bus_own_name (G_BUS_TYPE_SESSION,
306 : : name,
307 : : G_BUS_NAME_OWNER_FLAGS_NONE,
308 : : bus_acquired_handler,
309 : : name_acquired_handler,
310 : : name_lost_handler,
311 : : &data2,
312 : : (GDestroyNotify) own_name_data_free_func);
313 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
314 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
315 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
316 : :
317 : 3 : while (data2.num_bus_acquired < 1)
318 : 2 : g_main_context_iteration (main_context, TRUE);
319 : :
320 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 1);
321 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
322 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
323 : :
324 : 3 : while (data2.num_lost < 1)
325 : 2 : g_main_context_iteration (main_context, TRUE);
326 : :
327 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 1);
328 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
329 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
330 : :
331 : 1 : g_bus_unown_name (id2);
332 : 2 : while (data2.num_free_func < 1)
333 : 1 : g_main_context_iteration (main_context, TRUE);
334 : :
335 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 1);
336 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
337 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
338 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
339 : :
340 : : /*
341 : : * Create a secondary (e.g. private) connection and try owning the name on that
342 : : * connection. This should fail both with and without _REPLACE because we
343 : : * didn't specify ALLOW_REPLACEMENT.
344 : : */
345 : 1 : c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
346 : 1 : g_assert (c2 != NULL);
347 : 1 : g_assert (!g_dbus_connection_is_closed (c2));
348 : : /* first without _REPLACE */
349 : 1 : data2.num_bus_acquired = 0;
350 : 1 : data2.num_acquired = 0;
351 : 1 : data2.num_lost = 0;
352 : 1 : data2.expect_null_connection = FALSE;
353 : 1 : data2.num_free_func = 0;
354 : 1 : id2 = g_bus_own_name_on_connection (c2,
355 : : name,
356 : : G_BUS_NAME_OWNER_FLAGS_NONE,
357 : : name_acquired_handler,
358 : : name_lost_handler,
359 : : &data2,
360 : : (GDestroyNotify) own_name_data_free_func);
361 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
362 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
363 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
364 : :
365 : 3 : while (data2.num_lost < 1)
366 : 2 : g_main_context_iteration (main_context, TRUE);
367 : :
368 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
369 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
370 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
371 : :
372 : 1 : g_bus_unown_name (id2);
373 : 2 : while (data2.num_free_func < 1)
374 : 1 : g_main_context_iteration (main_context, TRUE);
375 : :
376 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
377 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
378 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
379 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
380 : : /* then with _REPLACE */
381 : 1 : data2.num_bus_acquired = 0;
382 : 1 : data2.num_acquired = 0;
383 : 1 : data2.num_lost = 0;
384 : 1 : data2.expect_null_connection = FALSE;
385 : 1 : data2.num_free_func = 0;
386 : 1 : id2 = g_bus_own_name_on_connection (c2,
387 : : name,
388 : : G_BUS_NAME_OWNER_FLAGS_REPLACE,
389 : : name_acquired_handler,
390 : : name_lost_handler,
391 : : &data2,
392 : : (GDestroyNotify) own_name_data_free_func);
393 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
394 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
395 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
396 : :
397 : 3 : while (data2.num_lost < 1)
398 : 2 : g_main_context_iteration (main_context, TRUE);
399 : :
400 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
401 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
402 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
403 : :
404 : 1 : g_bus_unown_name (id2);
405 : 2 : while (data2.num_free_func < 1)
406 : 1 : g_main_context_iteration (main_context, TRUE);
407 : :
408 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
409 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
410 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
411 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
412 : :
413 : : /*
414 : : * Stop owning the name and grab it again with _ALLOW_REPLACEMENT.
415 : : */
416 : 1 : data.expect_null_connection = FALSE;
417 : 1 : g_bus_unown_name (id);
418 : 3 : while (data.num_bus_acquired < 1 || data.num_free_func < 4)
419 : 2 : g_main_context_iteration (main_context, TRUE);
420 : :
421 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
422 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
423 : 1 : g_assert_cmpint (data.num_free_func, ==, 4);
424 : : /* grab it again */
425 : 1 : data.num_bus_acquired = 0;
426 : 1 : data.num_acquired = 0;
427 : 1 : data.num_lost = 0;
428 : 1 : data.expect_null_connection = FALSE;
429 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
430 : : name,
431 : : G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
432 : : bus_acquired_handler,
433 : : name_acquired_handler,
434 : : name_lost_handler,
435 : : &data,
436 : : (GDestroyNotify) own_name_data_free_func);
437 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
438 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
439 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
440 : :
441 : 3 : while (data.num_bus_acquired < 1)
442 : 2 : g_main_context_iteration (main_context, TRUE);
443 : :
444 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
445 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
446 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
447 : :
448 : 3 : while (data.num_acquired < 1)
449 : 2 : g_main_context_iteration (main_context, TRUE);
450 : :
451 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
452 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
453 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
454 : :
455 : : /*
456 : : * Now try to grab the name from the secondary connection.
457 : : *
458 : : */
459 : : /* first without _REPLACE - this won't make us acquire the name */
460 : 1 : data2.num_bus_acquired = 0;
461 : 1 : data2.num_acquired = 0;
462 : 1 : data2.num_lost = 0;
463 : 1 : data2.expect_null_connection = FALSE;
464 : 1 : data2.num_free_func = 0;
465 : 1 : id2 = g_bus_own_name_on_connection (c2,
466 : : name,
467 : : G_BUS_NAME_OWNER_FLAGS_NONE,
468 : : name_acquired_handler,
469 : : name_lost_handler,
470 : : &data2,
471 : : (GDestroyNotify) own_name_data_free_func);
472 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
473 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
474 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
475 : :
476 : 3 : while (data2.num_lost < 1)
477 : 2 : g_main_context_iteration (main_context, TRUE);
478 : :
479 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
480 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
481 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
482 : :
483 : 1 : g_bus_unown_name (id2);
484 : 2 : while (data2.num_free_func < 1)
485 : 1 : g_main_context_iteration (main_context, TRUE);
486 : :
487 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
488 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
489 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
490 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
491 : : /* then with _REPLACE - here we should acquire the name - e.g. owner should lose it
492 : : * and owner2 should acquire it */
493 : 1 : data2.num_bus_acquired = 0;
494 : 1 : data2.num_acquired = 0;
495 : 1 : data2.num_lost = 0;
496 : 1 : data2.expect_null_connection = FALSE;
497 : 1 : data2.num_free_func = 0;
498 : 1 : id2 = g_bus_own_name_on_connection (c2,
499 : : name,
500 : : G_BUS_NAME_OWNER_FLAGS_REPLACE,
501 : : name_acquired_handler,
502 : : name_lost_handler,
503 : : &data2,
504 : : (GDestroyNotify) own_name_data_free_func);
505 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
506 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
507 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
508 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
509 : :
510 : : /* wait for handlers for both owner and owner2 to fire */
511 : 3 : while (data.num_lost == 0 || data2.num_acquired == 0)
512 : 2 : g_main_context_iteration (main_context, TRUE);
513 : :
514 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
515 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
516 : 1 : g_assert_cmpint (data2.num_acquired, ==, 1);
517 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
518 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
519 : :
520 : : /* ok, make owner2 release the name - then wait for owner to automagically reacquire it */
521 : 1 : g_bus_unown_name (id2);
522 : 3 : while (data.num_acquired < 2 || data2.num_free_func < 1)
523 : 2 : g_main_context_iteration (main_context, TRUE);
524 : :
525 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
526 : 1 : g_assert_cmpint (data.num_acquired, ==, 2);
527 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
528 : :
529 : : /*
530 : : * Finally, nuke the bus and check name_lost_handler() is invoked.
531 : : *
532 : : */
533 : 1 : data.expect_null_connection = TRUE;
534 : 1 : session_bus_stop ();
535 : 3 : while (data.num_lost != 2)
536 : 2 : g_main_context_iteration (main_context, TRUE);
537 : :
538 : 1 : g_assert_cmpint (data.num_acquired, ==, 2);
539 : 1 : g_assert_cmpint (data.num_lost, ==, 2);
540 : :
541 : 1 : g_bus_unown_name (id);
542 : 2 : while (data.num_free_func < 5)
543 : 1 : g_main_context_iteration (main_context, TRUE);
544 : :
545 : 1 : g_assert_cmpint (data.num_free_func, ==, 5);
546 : :
547 : 1 : g_object_unref (c);
548 : 1 : g_object_unref (c2);
549 : :
550 : 1 : session_bus_down ();
551 : 1 : }
552 : :
553 : : /* ---------------------------------------------------------------------------------------------------- */
554 : : /* Test that g_bus_watch_name() works correctly */
555 : : /* ---------------------------------------------------------------------------------------------------- */
556 : :
557 : : typedef struct
558 : : {
559 : : gboolean expect_null_connection;
560 : : guint num_acquired;
561 : : guint num_lost;
562 : : guint num_appeared;
563 : : guint num_vanished;
564 : : guint num_free_func;
565 : : GMainContext *main_context; /* (unowned), for the main test thread */
566 : : } WatchNameData;
567 : :
568 : : typedef struct
569 : : {
570 : : WatchNameData data;
571 : : GDBusConnection *connection;
572 : : GMutex cond_mutex;
573 : : GCond cond;
574 : : gboolean started;
575 : : gboolean name_acquired;
576 : : gboolean ended;
577 : : gboolean unwatch_early;
578 : : GMutex mutex;
579 : : guint watch_id;
580 : : GMainContext *thread_context; /* (unowned), only accessed from watcher_thread() */
581 : : } WatchNameThreadData;
582 : :
583 : : static void
584 : 15 : watch_name_data_free_func (WatchNameData *data)
585 : : {
586 : 15 : data->num_free_func++;
587 : 15 : g_main_context_wakeup (data->main_context);
588 : 15 : }
589 : :
590 : : static void
591 : 9 : w_bus_acquired_handler (GDBusConnection *connection,
592 : : const gchar *name,
593 : : gpointer user_data)
594 : : {
595 : 9 : }
596 : :
597 : : static void
598 : 11 : w_name_acquired_handler (GDBusConnection *connection,
599 : : const gchar *name,
600 : : gpointer user_data)
601 : : {
602 : 11 : OwnNameData *data = user_data;
603 : 11 : data->num_acquired += 1;
604 : 11 : g_main_context_wakeup (data->main_context);
605 : 11 : }
606 : :
607 : : static void
608 : 6 : w_name_lost_handler (GDBusConnection *connection,
609 : : const gchar *name,
610 : : gpointer user_data)
611 : : {
612 : 6 : OwnNameData *data = user_data;
613 : 6 : data->num_lost += 1;
614 : 6 : g_main_context_wakeup (data->main_context);
615 : 6 : }
616 : :
617 : : static void
618 : 10 : name_appeared_handler (GDBusConnection *connection,
619 : : const gchar *name,
620 : : const gchar *name_owner,
621 : : gpointer user_data)
622 : : {
623 : 10 : WatchNameData *data = user_data;
624 : :
625 : 10 : if (data->expect_null_connection)
626 : : {
627 : 0 : g_assert (connection == NULL);
628 : : }
629 : : else
630 : : {
631 : 10 : g_assert (connection != NULL);
632 : 10 : g_dbus_connection_set_exit_on_close (connection, FALSE);
633 : : }
634 : 10 : data->num_appeared += 1;
635 : 10 : g_main_context_wakeup (data->main_context);
636 : 10 : }
637 : :
638 : : static void
639 : 14 : name_vanished_handler (GDBusConnection *connection,
640 : : const gchar *name,
641 : : gpointer user_data)
642 : : {
643 : 14 : WatchNameData *data = user_data;
644 : :
645 : 14 : if (data->expect_null_connection)
646 : : {
647 : 9 : g_assert (connection == NULL);
648 : : }
649 : : else
650 : : {
651 : 5 : g_assert (connection != NULL);
652 : 5 : g_dbus_connection_set_exit_on_close (connection, FALSE);
653 : : }
654 : 14 : data->num_vanished += 1;
655 : 14 : g_main_context_wakeup (data->main_context);
656 : 14 : }
657 : :
658 : : typedef struct
659 : : {
660 : : guint watcher_flags;
661 : : gboolean watch_with_closures;
662 : : gboolean existing_service;
663 : : } WatchNameTest;
664 : :
665 : : static const WatchNameTest watch_no_closures_no_flags = {
666 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
667 : : .watch_with_closures = FALSE,
668 : : .existing_service = FALSE
669 : : };
670 : :
671 : : static const WatchNameTest watch_no_closures_flags_auto_start = {
672 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
673 : : .watch_with_closures = FALSE,
674 : : .existing_service = FALSE
675 : : };
676 : :
677 : : static const WatchNameTest watch_no_closures_flags_auto_start_service_exist = {
678 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
679 : : .watch_with_closures = FALSE,
680 : : .existing_service = TRUE
681 : : };
682 : :
683 : : static const WatchNameTest watch_closures_no_flags = {
684 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
685 : : .watch_with_closures = TRUE,
686 : : .existing_service = FALSE
687 : : };
688 : :
689 : : static const WatchNameTest watch_closures_flags_auto_start = {
690 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
691 : : .watch_with_closures = TRUE,
692 : : .existing_service = FALSE
693 : : };
694 : :
695 : : static void
696 : 1 : stop_service (GDBusConnection *connection,
697 : : WatchNameData *data)
698 : : {
699 : 1 : GError *error = NULL;
700 : 1 : GDBusProxy *proxy = NULL;
701 : 1 : GVariant *result = NULL;
702 : 1 : GMainContext *main_context = NULL; /* use the global default for now */
703 : :
704 : 1 : data->num_vanished = 0;
705 : :
706 : 1 : proxy = g_dbus_proxy_new_sync (connection,
707 : : G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
708 : : NULL,
709 : : "org.gtk.GDBus.FakeService",
710 : : "/org/gtk/GDBus/FakeService",
711 : : "org.gtk.GDBus.FakeService",
712 : : NULL,
713 : : &error);
714 : 1 : g_assert_no_error (error);
715 : :
716 : 1 : result = g_dbus_proxy_call_sync (proxy,
717 : : "Quit",
718 : : NULL,
719 : : G_DBUS_CALL_FLAGS_NO_AUTO_START,
720 : : 100,
721 : : NULL,
722 : : &error);
723 : 1 : g_assert_no_error (error);
724 : 1 : g_object_unref (proxy);
725 : 1 : if (result)
726 : 1 : g_variant_unref (result);
727 : 3 : while (data->num_vanished == 0)
728 : 2 : g_main_context_iteration (main_context, TRUE);
729 : 1 : }
730 : :
731 : : static void
732 : 5 : test_bus_watch_name (gconstpointer d)
733 : : {
734 : : WatchNameData data;
735 : : OwnNameData own_data;
736 : : guint id;
737 : : guint owner_id;
738 : : GDBusConnection *connection;
739 : : const WatchNameTest *watch_name_test;
740 : : const gchar *name;
741 : 5 : GMainContext *main_context = NULL; /* use the global default for now */
742 : :
743 : 5 : watch_name_test = (WatchNameTest *) d;
744 : :
745 : 5 : if (watch_name_test->existing_service)
746 : : {
747 : 1 : name = "org.gtk.GDBus.FakeService";
748 : : }
749 : : else
750 : : {
751 : 4 : name = "org.gtk.GDBus.Name1";
752 : : }
753 : :
754 : : /*
755 : : * First check that name_vanished_handler() is invoked if there is no bus.
756 : : *
757 : : * Also make sure name_vanished_handler() isn't invoked when unwatching the name.
758 : : */
759 : 5 : data.num_free_func = 0;
760 : 5 : data.num_appeared = 0;
761 : 5 : data.num_vanished = 0;
762 : 5 : data.expect_null_connection = TRUE;
763 : 5 : data.main_context = main_context;
764 : 5 : id = g_bus_watch_name (G_BUS_TYPE_SESSION,
765 : : name,
766 : 5 : watch_name_test->watcher_flags,
767 : : name_appeared_handler,
768 : : name_vanished_handler,
769 : : &data,
770 : : (GDestroyNotify) watch_name_data_free_func);
771 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
772 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
773 : :
774 : 10 : while (data.num_vanished < 1)
775 : 5 : g_main_context_iteration (main_context, TRUE);
776 : :
777 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
778 : 5 : g_assert_cmpint (data.num_vanished, ==, 1);
779 : :
780 : 5 : g_bus_unwatch_name (id);
781 : 10 : while (data.num_free_func < 1)
782 : 5 : g_main_context_iteration (main_context, TRUE);
783 : :
784 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
785 : 5 : g_assert_cmpint (data.num_vanished, ==, 1);
786 : 5 : g_assert_cmpint (data.num_free_func, ==, 1);
787 : 5 : data.num_free_func = 0;
788 : :
789 : : /*
790 : : * Now bring up a bus, own a name, and then start watching it.
791 : : */
792 : 5 : session_bus_up ();
793 : : /* own the name */
794 : 5 : own_data.num_free_func = 0;
795 : 5 : own_data.num_acquired = 0;
796 : 5 : own_data.num_lost = 0;
797 : 5 : data.expect_null_connection = FALSE;
798 : 5 : own_data.main_context = main_context;
799 : 5 : owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
800 : : name,
801 : : G_BUS_NAME_OWNER_FLAGS_NONE,
802 : : w_bus_acquired_handler,
803 : : w_name_acquired_handler,
804 : : w_name_lost_handler,
805 : : &own_data,
806 : : (GDestroyNotify) own_name_data_free_func);
807 : :
808 : 20 : while (own_data.num_acquired < 1)
809 : 15 : g_main_context_iteration (main_context, TRUE);
810 : :
811 : 5 : g_assert_cmpint (own_data.num_acquired, ==, 1);
812 : 5 : g_assert_cmpint (own_data.num_lost, ==, 0);
813 : :
814 : 5 : connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
815 : 5 : g_assert (connection != NULL);
816 : :
817 : : /* now watch the name */
818 : 5 : data.num_appeared = 0;
819 : 5 : data.num_vanished = 0;
820 : 5 : if (watch_name_test->watch_with_closures)
821 : : {
822 : 2 : id = g_bus_watch_name_on_connection_with_closures (connection,
823 : : name,
824 : 2 : watch_name_test->watcher_flags,
825 : : g_cclosure_new (G_CALLBACK (name_appeared_handler),
826 : : &data,
827 : : NULL),
828 : : g_cclosure_new (G_CALLBACK (name_vanished_handler),
829 : : &data,
830 : : (GClosureNotify) watch_name_data_free_func));
831 : : }
832 : : else
833 : : {
834 : 3 : id = g_bus_watch_name_on_connection (connection,
835 : : name,
836 : 3 : watch_name_test->watcher_flags,
837 : : name_appeared_handler,
838 : : name_vanished_handler,
839 : : &data,
840 : : (GDestroyNotify) watch_name_data_free_func);
841 : : }
842 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
843 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
844 : :
845 : 18 : while (data.num_appeared < 1)
846 : 13 : g_main_context_iteration (main_context, TRUE);
847 : :
848 : 5 : g_assert_cmpint (data.num_appeared, ==, 1);
849 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
850 : :
851 : : /*
852 : : * Unwatch the name.
853 : : */
854 : 5 : g_bus_unwatch_name (id);
855 : 10 : while (data.num_free_func < 1)
856 : 5 : g_main_context_iteration (main_context, TRUE);
857 : :
858 : 5 : g_assert_cmpint (data.num_free_func, ==, 1);
859 : :
860 : : /* unown the name */
861 : 5 : g_bus_unown_name (owner_id);
862 : 15 : while (own_data.num_free_func < 1)
863 : 10 : g_main_context_iteration (main_context, TRUE);
864 : :
865 : 5 : g_assert_cmpint (own_data.num_acquired, ==, 1);
866 : 5 : g_assert_cmpint (own_data.num_free_func, ==, 1);
867 : 5 : own_data.num_free_func = 0;
868 : : /*
869 : : * Create a watcher and then make a name be owned.
870 : : *
871 : : * This should trigger name_appeared_handler() ...
872 : : */
873 : : /* watch the name */
874 : 5 : data.num_appeared = 0;
875 : 5 : data.num_vanished = 0;
876 : 5 : data.num_free_func = 0;
877 : 5 : if (watch_name_test->watch_with_closures)
878 : : {
879 : 2 : id = g_bus_watch_name_with_closures (G_BUS_TYPE_SESSION,
880 : : name,
881 : 2 : watch_name_test->watcher_flags,
882 : : g_cclosure_new (G_CALLBACK (name_appeared_handler),
883 : : &data,
884 : : NULL),
885 : : g_cclosure_new (G_CALLBACK (name_vanished_handler),
886 : : &data,
887 : : (GClosureNotify) watch_name_data_free_func));
888 : : }
889 : : else
890 : : {
891 : 3 : id = g_bus_watch_name (G_BUS_TYPE_SESSION,
892 : : name,
893 : 3 : watch_name_test->watcher_flags,
894 : : name_appeared_handler,
895 : : name_vanished_handler,
896 : : &data,
897 : : (GDestroyNotify) watch_name_data_free_func);
898 : : }
899 : :
900 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
901 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
902 : :
903 : 24 : while (data.num_appeared == 0 && data.num_vanished == 0)
904 : 19 : g_main_context_iteration (main_context, TRUE);
905 : :
906 : 5 : if (watch_name_test->existing_service)
907 : : {
908 : 1 : g_assert_cmpint (data.num_appeared, ==, 1);
909 : 1 : g_assert_cmpint (data.num_vanished, ==, 0);
910 : : }
911 : : else
912 : : {
913 : 4 : g_assert_cmpint (data.num_appeared, ==, 0);
914 : 4 : g_assert_cmpint (data.num_vanished, ==, 1);
915 : : }
916 : :
917 : 5 : if (!watch_name_test->existing_service)
918 : : {
919 : : /* own the name */
920 : 4 : own_data.num_acquired = 0;
921 : 4 : own_data.num_lost = 0;
922 : 4 : own_data.expect_null_connection = FALSE;
923 : 4 : own_data.main_context = main_context;
924 : 4 : owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
925 : : name,
926 : : G_BUS_NAME_OWNER_FLAGS_NONE,
927 : : w_bus_acquired_handler,
928 : : w_name_acquired_handler,
929 : : w_name_lost_handler,
930 : : &own_data,
931 : : (GDestroyNotify) own_name_data_free_func);
932 : :
933 : 24 : while (own_data.num_acquired == 0 || data.num_appeared == 0)
934 : 20 : g_main_context_iteration (main_context, TRUE);
935 : :
936 : 4 : g_assert_cmpint (own_data.num_acquired, ==, 1);
937 : 4 : g_assert_cmpint (own_data.num_lost, ==, 0);
938 : 4 : g_assert_cmpint (data.num_appeared, ==, 1);
939 : 4 : g_assert_cmpint (data.num_vanished, ==, 1);
940 : : }
941 : :
942 : 5 : data.expect_null_connection = TRUE;
943 : 5 : if (watch_name_test->existing_service)
944 : : {
945 : 1 : data.expect_null_connection = FALSE;
946 : 1 : stop_service (connection, &data);
947 : : }
948 : 5 : g_object_unref (connection);
949 : : /*
950 : : * Nuke the bus and check that the name vanishes and is lost.
951 : : */
952 : 5 : session_bus_stop ();
953 : 5 : if (!watch_name_test->existing_service)
954 : : {
955 : 16 : while (own_data.num_lost < 1 || data.num_vanished < 2)
956 : 12 : g_main_context_iteration (main_context, TRUE);
957 : 4 : g_assert_cmpint (own_data.num_lost, ==, 1);
958 : 4 : g_assert_cmpint (data.num_vanished, ==, 2);
959 : : }
960 : : else
961 : : {
962 : 1 : g_assert_cmpint (own_data.num_lost, ==, 0);
963 : 1 : g_assert_cmpint (data.num_vanished, ==, 1);
964 : : }
965 : :
966 : 5 : g_bus_unwatch_name (id);
967 : 14 : while (data.num_free_func < 1)
968 : 9 : g_main_context_iteration (main_context, TRUE);
969 : :
970 : 5 : g_assert_cmpint (data.num_free_func, ==, 1);
971 : :
972 : 5 : if (!watch_name_test->existing_service)
973 : : {
974 : 4 : g_bus_unown_name (owner_id);
975 : 4 : while (own_data.num_free_func < 1)
976 : 0 : g_main_context_iteration (main_context, TRUE);
977 : :
978 : 4 : g_assert_cmpint (own_data.num_free_func, ==, 1);
979 : : }
980 : 5 : session_bus_down ();
981 : 5 : }
982 : :
983 : : /* ---------------------------------------------------------------------------------------------------- */
984 : :
985 : : /* Called in the same thread as watcher_thread() */
986 : : static void
987 : 2 : t_watch_name_data_free_func (WatchNameThreadData *thread_data)
988 : : {
989 : 2 : thread_data->data.num_free_func++;
990 : :
991 : 2 : g_assert_true (g_main_context_is_owner (thread_data->thread_context));
992 : 2 : g_main_context_wakeup (thread_data->thread_context);
993 : 2 : }
994 : :
995 : : /* Called in the same thread as watcher_thread() */
996 : : static void
997 : 2 : t_name_appeared_handler (GDBusConnection *connection,
998 : : const gchar *name,
999 : : const gchar *name_owner,
1000 : : gpointer user_data)
1001 : : {
1002 : 2 : WatchNameThreadData *thread_data = user_data;
1003 : 2 : thread_data->data.num_appeared += 1;
1004 : :
1005 : 2 : g_assert_true (g_main_context_is_owner (thread_data->thread_context));
1006 : 2 : g_main_context_wakeup (thread_data->thread_context);
1007 : 2 : }
1008 : :
1009 : : /* Called in the same thread as watcher_thread() */
1010 : : static void
1011 : 1 : t_name_vanished_handler (GDBusConnection *connection,
1012 : : const gchar *name,
1013 : : gpointer user_data)
1014 : : {
1015 : 1 : WatchNameThreadData *thread_data = user_data;
1016 : 1 : thread_data->data.num_vanished += 1;
1017 : :
1018 : 1 : g_assert_true (g_main_context_is_owner (thread_data->thread_context));
1019 : 1 : g_main_context_wakeup (thread_data->thread_context);
1020 : 1 : }
1021 : :
1022 : : /* Called in the thread which constructed the GDBusConnection */
1023 : : static void
1024 : 2 : connection_closed_cb (GDBusConnection *connection,
1025 : : gboolean remote_peer_vanished,
1026 : : GError *error,
1027 : : gpointer user_data)
1028 : : {
1029 : 2 : WatchNameThreadData *thread_data = (WatchNameThreadData *) user_data;
1030 : 2 : if (thread_data->unwatch_early)
1031 : : {
1032 : 1 : g_mutex_lock (&thread_data->mutex);
1033 : 1 : g_bus_unwatch_name (g_atomic_int_get (&thread_data->watch_id));
1034 : 1 : g_atomic_int_set (&thread_data->watch_id, 0);
1035 : 1 : g_cond_signal (&thread_data->cond);
1036 : 1 : g_mutex_unlock (&thread_data->mutex);
1037 : : }
1038 : 2 : }
1039 : :
1040 : : static gpointer
1041 : 2 : watcher_thread (gpointer user_data)
1042 : : {
1043 : 2 : WatchNameThreadData *thread_data = user_data;
1044 : : GMainContext *thread_context;
1045 : :
1046 : 2 : thread_context = g_main_context_new ();
1047 : 2 : thread_data->thread_context = thread_context;
1048 : 2 : g_main_context_push_thread_default (thread_context);
1049 : :
1050 : : // Notify that the thread has started
1051 : 2 : g_mutex_lock (&thread_data->cond_mutex);
1052 : 2 : g_atomic_int_set (&thread_data->started, TRUE);
1053 : 2 : g_cond_signal (&thread_data->cond);
1054 : 2 : g_mutex_unlock (&thread_data->cond_mutex);
1055 : :
1056 : : // Wait for the main thread to own the name before watching it
1057 : 2 : g_mutex_lock (&thread_data->cond_mutex);
1058 : 4 : while (!g_atomic_int_get (&thread_data->name_acquired))
1059 : 2 : g_cond_wait (&thread_data->cond, &thread_data->cond_mutex);
1060 : 2 : g_mutex_unlock (&thread_data->cond_mutex);
1061 : :
1062 : 2 : thread_data->data.num_appeared = 0;
1063 : 2 : thread_data->data.num_vanished = 0;
1064 : 2 : thread_data->data.num_free_func = 0;
1065 : : // g_signal_connect_after is important to have default handler be called before our code
1066 : 2 : g_signal_connect_after (thread_data->connection, "closed", G_CALLBACK (connection_closed_cb), thread_data);
1067 : :
1068 : 2 : g_mutex_lock (&thread_data->mutex);
1069 : 2 : thread_data->watch_id = g_bus_watch_name_on_connection (thread_data->connection,
1070 : : "org.gtk.GDBus.Name1",
1071 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
1072 : : t_name_appeared_handler,
1073 : : t_name_vanished_handler,
1074 : : thread_data,
1075 : : (GDestroyNotify) t_watch_name_data_free_func);
1076 : 2 : g_mutex_unlock (&thread_data->mutex);
1077 : :
1078 : 2 : g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1079 : 2 : g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1080 : 4 : while (thread_data->data.num_appeared == 0)
1081 : 2 : g_main_context_iteration (thread_context, TRUE);
1082 : 2 : g_assert_cmpint (thread_data->data.num_appeared, ==, 1);
1083 : 2 : g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1084 : 2 : thread_data->data.num_appeared = 0;
1085 : :
1086 : : /* Close the connection and:
1087 : : * - check that we had received a vanished event even begin in different thread
1088 : : * - or check that unwatching the bus when a vanished had been scheduled
1089 : : * make it correctly unscheduled (unwatch_early condition)
1090 : : */
1091 : 2 : g_dbus_connection_close_sync (thread_data->connection, NULL, NULL);
1092 : 2 : if (thread_data->unwatch_early)
1093 : : {
1094 : : // Wait for the main thread to iterate in order to have close connection handled
1095 : 1 : g_mutex_lock (&thread_data->mutex);
1096 : 2 : while (g_atomic_int_get (&thread_data->watch_id) != 0)
1097 : 1 : g_cond_wait (&thread_data->cond, &thread_data->mutex);
1098 : 1 : g_mutex_unlock (&thread_data->mutex);
1099 : :
1100 : 2 : while (thread_data->data.num_free_func == 0)
1101 : 1 : g_main_context_iteration (thread_context, TRUE);
1102 : 1 : g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1103 : 1 : g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1104 : 1 : g_assert_cmpint (thread_data->data.num_free_func, ==, 1);
1105 : : }
1106 : : else
1107 : : {
1108 : 3 : while (thread_data->data.num_vanished == 0)
1109 : : {
1110 : : /*
1111 : : * Close of connection is treated in the context of the thread which
1112 : : * creates the connection. We must run iteration on it (to have the 'closed'
1113 : : * signal handled) and also run current thread loop to have name_vanished
1114 : : * callback handled.
1115 : : */
1116 : 2 : g_main_context_iteration (thread_context, TRUE);
1117 : : }
1118 : 1 : g_assert_cmpint (thread_data->data.num_vanished, ==, 1);
1119 : 1 : g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1120 : 1 : g_mutex_lock (&thread_data->mutex);
1121 : 1 : g_bus_unwatch_name (g_atomic_int_get (&thread_data->watch_id));
1122 : 1 : g_atomic_int_set (&thread_data->watch_id, 0);
1123 : 1 : g_mutex_unlock (&thread_data->mutex);
1124 : 1 : while (thread_data->data.num_free_func == 0)
1125 : 0 : g_main_context_iteration (thread_context, TRUE);
1126 : 1 : g_assert_cmpint (thread_data->data.num_free_func, ==, 1);
1127 : : }
1128 : :
1129 : 2 : g_mutex_lock (&thread_data->cond_mutex);
1130 : 2 : thread_data->ended = TRUE;
1131 : 2 : g_main_context_wakeup (NULL);
1132 : 2 : g_cond_signal (&thread_data->cond);
1133 : 2 : g_mutex_unlock (&thread_data->cond_mutex);
1134 : :
1135 : 2 : g_signal_handlers_disconnect_by_func (thread_data->connection, connection_closed_cb, thread_data);
1136 : 2 : g_object_unref (thread_data->connection);
1137 : 2 : g_main_context_pop_thread_default (thread_context);
1138 : 2 : g_main_context_unref (thread_context);
1139 : :
1140 : 2 : g_mutex_lock (&thread_data->mutex);
1141 : 2 : g_assert_cmpint (thread_data->watch_id, ==, 0);
1142 : 2 : g_mutex_unlock (&thread_data->mutex);
1143 : 2 : return NULL;
1144 : : }
1145 : :
1146 : : static void
1147 : 2 : watch_with_different_context (gboolean unwatch_early)
1148 : : {
1149 : : OwnNameData own_data;
1150 : : WatchNameThreadData thread_data;
1151 : : GDBusConnection *connection;
1152 : : GThread *watcher;
1153 : : guint id;
1154 : 2 : GMainContext *main_context = NULL; /* use the global default for now */
1155 : :
1156 : 2 : session_bus_up ();
1157 : :
1158 : 2 : connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
1159 : 2 : g_assert (connection != NULL);
1160 : :
1161 : 2 : g_mutex_init (&thread_data.mutex);
1162 : 2 : g_mutex_init (&thread_data.cond_mutex);
1163 : 2 : g_cond_init (&thread_data.cond);
1164 : 2 : thread_data.started = FALSE;
1165 : 2 : thread_data.name_acquired = FALSE;
1166 : 2 : thread_data.ended = FALSE;
1167 : 2 : thread_data.connection = g_object_ref (connection);
1168 : 2 : thread_data.unwatch_early = unwatch_early;
1169 : :
1170 : : // Create a thread which will watch a name and wait for it to be ready
1171 : 2 : g_mutex_lock (&thread_data.cond_mutex);
1172 : 2 : watcher = g_thread_new ("watcher", watcher_thread, &thread_data);
1173 : 4 : while (!g_atomic_int_get (&thread_data.started))
1174 : 2 : g_cond_wait (&thread_data.cond, &thread_data.cond_mutex);
1175 : 2 : g_mutex_unlock (&thread_data.cond_mutex);
1176 : :
1177 : 2 : own_data.num_acquired = 0;
1178 : 2 : own_data.num_lost = 0;
1179 : 2 : own_data.num_free_func = 0;
1180 : 2 : own_data.expect_null_connection = FALSE;
1181 : 2 : own_data.main_context = main_context;
1182 : : // Own the name to avoid direct name vanished in watcher thread
1183 : 2 : id = g_bus_own_name_on_connection (connection,
1184 : : "org.gtk.GDBus.Name1",
1185 : : G_BUS_NAME_OWNER_FLAGS_REPLACE,
1186 : : w_name_acquired_handler,
1187 : : w_name_lost_handler,
1188 : : &own_data,
1189 : : (GDestroyNotify) own_name_data_free_func);
1190 : 6 : while (own_data.num_acquired == 0)
1191 : 4 : g_main_context_iteration (main_context, TRUE);
1192 : 2 : g_assert_cmpint (own_data.num_acquired, ==, 1);
1193 : 2 : g_assert_cmpint (own_data.num_lost, ==, 0);
1194 : :
1195 : : // Wake the thread for it to begin watch
1196 : 2 : g_mutex_lock (&thread_data.cond_mutex);
1197 : 2 : g_atomic_int_set (&thread_data.name_acquired, TRUE);
1198 : 2 : g_cond_signal (&thread_data.cond);
1199 : 2 : g_mutex_unlock (&thread_data.cond_mutex);
1200 : :
1201 : : // Iterate the loop until thread is waking us up
1202 : 10 : while (!thread_data.ended)
1203 : 8 : g_main_context_iteration (main_context, TRUE);
1204 : :
1205 : 2 : g_thread_join (watcher);
1206 : :
1207 : 2 : g_bus_unown_name (id);
1208 : 2 : while (own_data.num_free_func == 0)
1209 : 0 : g_main_context_iteration (main_context, TRUE);
1210 : 2 : g_assert_cmpint (own_data.num_free_func, ==, 1);
1211 : :
1212 : 2 : g_mutex_clear (&thread_data.mutex);
1213 : 2 : g_mutex_clear (&thread_data.cond_mutex);
1214 : 2 : g_cond_clear (&thread_data.cond);
1215 : :
1216 : 2 : session_bus_stop ();
1217 : 2 : g_assert_true (g_dbus_connection_is_closed (connection));
1218 : 2 : g_object_unref (connection);
1219 : 2 : session_bus_down ();
1220 : 2 : }
1221 : :
1222 : : static void
1223 : 1 : test_bus_watch_different_context (void)
1224 : : {
1225 : 1 : watch_with_different_context (FALSE);
1226 : 1 : }
1227 : :
1228 : : /* ---------------------------------------------------------------------------------------------------- */
1229 : :
1230 : : static void
1231 : 1 : test_bus_unwatch_early (void)
1232 : : {
1233 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/604");
1234 : 1 : watch_with_different_context (TRUE);
1235 : 1 : }
1236 : :
1237 : : /* ---------------------------------------------------------------------------------------------------- */
1238 : :
1239 : : static void
1240 : 1 : test_validate_names (void)
1241 : : {
1242 : : guint n;
1243 : : static const struct
1244 : : {
1245 : : gboolean name;
1246 : : gboolean unique;
1247 : : gboolean interface;
1248 : : const gchar *string;
1249 : : } names[] = {
1250 : : { 1, 0, 1, "valid.well_known.name"},
1251 : : { 1, 0, 0, "valid.well-known.name"},
1252 : : { 1, 1, 0, ":valid.unique.name"},
1253 : : { 0, 0, 0, "invalid.5well_known.name"},
1254 : : { 0, 0, 0, "4invalid.5well_known.name"},
1255 : : { 1, 1, 0, ":4valid.5unique.name"},
1256 : : { 0, 0, 0, ""},
1257 : : { 1, 0, 1, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name1"}, /* 255 */
1258 : : { 0, 0, 0, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name12"}, /* 256 - too long! */
1259 : : { 0, 0, 0, ".starts.with.a.dot"},
1260 : : { 0, 0, 0, "contains.invalid;.characters"},
1261 : : { 0, 0, 0, "contains.inva/lid.characters"},
1262 : : { 0, 0, 0, "contains.inva[lid.characters"},
1263 : : { 0, 0, 0, "contains.inva]lid.characters"},
1264 : : { 0, 0, 0, "contains.inva_æøå_lid.characters"},
1265 : : { 1, 1, 0, ":1.1"},
1266 : : };
1267 : :
1268 : 17 : for (n = 0; n < G_N_ELEMENTS (names); n++)
1269 : : {
1270 : 16 : if (names[n].name)
1271 : 6 : g_assert (g_dbus_is_name (names[n].string));
1272 : : else
1273 : 10 : g_assert (!g_dbus_is_name (names[n].string));
1274 : :
1275 : 16 : if (names[n].unique)
1276 : 3 : g_assert (g_dbus_is_unique_name (names[n].string));
1277 : : else
1278 : 13 : g_assert (!g_dbus_is_unique_name (names[n].string));
1279 : :
1280 : 16 : if (names[n].interface)
1281 : : {
1282 : 2 : g_assert (g_dbus_is_interface_name (names[n].string));
1283 : 2 : g_assert (g_dbus_is_error_name (names[n].string));
1284 : : }
1285 : : else
1286 : : {
1287 : 14 : g_assert (!g_dbus_is_interface_name (names[n].string));
1288 : 14 : g_assert (!g_dbus_is_error_name (names[n].string));
1289 : : }
1290 : : }
1291 : 1 : }
1292 : :
1293 : : static void
1294 : 10 : assert_cmp_escaped_object_path (const gchar *s,
1295 : : const gchar *correct_escaped)
1296 : : {
1297 : : gchar *escaped;
1298 : : guint8 *unescaped;
1299 : :
1300 : 10 : escaped = g_dbus_escape_object_path (s);
1301 : 10 : g_assert_cmpstr (escaped, ==, correct_escaped);
1302 : :
1303 : 10 : g_free (escaped);
1304 : 10 : escaped = g_dbus_escape_object_path_bytestring ((const guint8 *) s);
1305 : 10 : g_assert_cmpstr (escaped, ==, correct_escaped);
1306 : :
1307 : 10 : unescaped = g_dbus_unescape_object_path (escaped);
1308 : 10 : g_assert_cmpstr ((const gchar *) unescaped, ==, s);
1309 : :
1310 : 10 : g_free (escaped);
1311 : 10 : g_free (unescaped);
1312 : 10 : }
1313 : :
1314 : : static void
1315 : 1 : test_escape_object_path (void)
1316 : : {
1317 : 1 : assert_cmp_escaped_object_path ("Foo42", "Foo42");
1318 : 1 : assert_cmp_escaped_object_path ("foo.bar.baz", "foo_2ebar_2ebaz");
1319 : 1 : assert_cmp_escaped_object_path ("foo_bar_baz", "foo_5fbar_5fbaz");
1320 : 1 : assert_cmp_escaped_object_path ("_", "_5f");
1321 : 1 : assert_cmp_escaped_object_path ("__", "_5f_5f");
1322 : 1 : assert_cmp_escaped_object_path ("", "_");
1323 : 1 : assert_cmp_escaped_object_path (":1.42", "_3a1_2e42");
1324 : 1 : assert_cmp_escaped_object_path ("a/b", "a_2fb");
1325 : 1 : assert_cmp_escaped_object_path (" ", "_20");
1326 : 1 : assert_cmp_escaped_object_path ("\n", "_0a");
1327 : :
1328 : 1 : g_assert_null (g_dbus_unescape_object_path ("_ii"));
1329 : 1 : g_assert_null (g_dbus_unescape_object_path ("döner"));
1330 : 1 : g_assert_null (g_dbus_unescape_object_path ("_00"));
1331 : 1 : g_assert_null (g_dbus_unescape_object_path ("_61"));
1332 : 1 : g_assert_null (g_dbus_unescape_object_path ("_ga"));
1333 : 1 : g_assert_null (g_dbus_unescape_object_path ("_ag"));
1334 : 1 : }
1335 : :
1336 : : /* ---------------------------------------------------------------------------------------------------- */
1337 : :
1338 : : int
1339 : 1 : main (int argc,
1340 : : char *argv[])
1341 : : {
1342 : : gint ret;
1343 : :
1344 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1345 : :
1346 : 1 : g_test_dbus_unset ();
1347 : :
1348 : 1 : g_test_add_func ("/gdbus/validate-names", test_validate_names);
1349 : 1 : g_test_add_func ("/gdbus/bus-own-name", test_bus_own_name);
1350 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name",
1351 : : &watch_no_closures_no_flags,
1352 : : test_bus_watch_name);
1353 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-auto-start",
1354 : : &watch_no_closures_flags_auto_start,
1355 : : test_bus_watch_name);
1356 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-auto-start-service-exist",
1357 : : &watch_no_closures_flags_auto_start_service_exist,
1358 : : test_bus_watch_name);
1359 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-closures",
1360 : : &watch_closures_no_flags,
1361 : : test_bus_watch_name);
1362 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-closures-auto-start",
1363 : : &watch_closures_flags_auto_start,
1364 : : test_bus_watch_name);
1365 : 1 : g_test_add_func ("/gdbus/bus-watch-different-context", test_bus_watch_different_context);
1366 : 1 : g_test_add_func ("/gdbus/bus-unwatch-early", test_bus_unwatch_early);
1367 : 1 : g_test_add_func ("/gdbus/escape-object-path", test_escape_object_path);
1368 : 1 : ret = g_test_run();
1369 : :
1370 : 1 : return ret;
1371 : : }
|