Add some more cases to the app-id unit tests
[glib.git] / gio / gdbusaddress.c
blob9b3619cb1f737434d0eb4145d7431b54f31eb546
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
28 #include "gioerror.h"
29 #include "gdbusutils.h"
30 #include "gdbusaddress.h"
31 #include "gdbuserror.h"
32 #include "gioenumtypes.h"
33 #include "gnetworkaddress.h"
34 #include "gsocketclient.h"
35 #include "giostream.h"
36 #include "gasyncresult.h"
37 #include "gtask.h"
38 #include "glib-private.h"
39 #include "gdbusprivate.h"
40 #include "giomodule-priv.h"
41 #include "gdbusdaemon.h"
42 #include "gstdio.h"
44 #ifdef G_OS_UNIX
45 #include <unistd.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <gio/gunixsocketaddress.h>
49 #endif
51 #ifdef G_OS_WIN32
52 #include <windows.h>
53 #include <io.h>
54 #include <conio.h>
55 #endif
57 #include "glibintl.h"
59 /**
60 * SECTION:gdbusaddress
61 * @title: D-Bus Addresses
62 * @short_description: D-Bus connection endpoints
63 * @include: gio/gio.h
65 * Routines for working with D-Bus addresses. A D-Bus address is a string
66 * like `unix:tmpdir=/tmp/my-app-name`. The exact format of addresses
67 * is explained in detail in the
68 * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
71 static gchar *get_session_address_platform_specific (GError **error);
72 static gchar *get_session_address_dbus_launch (GError **error);
74 /* ---------------------------------------------------------------------------------------------------- */
76 /**
77 * g_dbus_is_address:
78 * @string: A string.
80 * Checks if @string is a
81 * [D-Bus address](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
83 * This doesn't check if @string is actually supported by #GDBusServer
84 * or #GDBusConnection - use g_dbus_is_supported_address() to do more
85 * checks.
87 * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
89 * Since: 2.26
91 gboolean
92 g_dbus_is_address (const gchar *string)
94 guint n;
95 gchar **a;
96 gboolean ret;
98 ret = FALSE;
100 g_return_val_if_fail (string != NULL, FALSE);
102 a = g_strsplit (string, ";", 0);
103 if (a[0] == NULL)
104 goto out;
106 for (n = 0; a[n] != NULL; n++)
108 if (!_g_dbus_address_parse_entry (a[n],
109 NULL,
110 NULL,
111 NULL))
112 goto out;
115 ret = TRUE;
117 out:
118 g_strfreev (a);
119 return ret;
122 static gboolean
123 is_valid_unix (const gchar *address_entry,
124 GHashTable *key_value_pairs,
125 GError **error)
127 gboolean ret;
128 GList *keys;
129 GList *l;
130 const gchar *path;
131 const gchar *tmpdir;
132 const gchar *abstract;
134 ret = FALSE;
135 keys = NULL;
136 path = NULL;
137 tmpdir = NULL;
138 abstract = NULL;
140 keys = g_hash_table_get_keys (key_value_pairs);
141 for (l = keys; l != NULL; l = l->next)
143 const gchar *key = l->data;
144 if (g_strcmp0 (key, "path") == 0)
145 path = g_hash_table_lookup (key_value_pairs, key);
146 else if (g_strcmp0 (key, "tmpdir") == 0)
147 tmpdir = g_hash_table_lookup (key_value_pairs, key);
148 else if (g_strcmp0 (key, "abstract") == 0)
149 abstract = g_hash_table_lookup (key_value_pairs, key);
150 else
152 g_set_error (error,
153 G_IO_ERROR,
154 G_IO_ERROR_INVALID_ARGUMENT,
155 _("Unsupported key “%s” in address entry “%s”"),
156 key,
157 address_entry);
158 goto out;
162 if (path != NULL)
164 if (tmpdir != NULL || abstract != NULL)
165 goto meaningless;
167 else if (tmpdir != NULL)
169 if (path != NULL || abstract != NULL)
170 goto meaningless;
172 else if (abstract != NULL)
174 if (path != NULL || tmpdir != NULL)
175 goto meaningless;
177 else
179 g_set_error (error,
180 G_IO_ERROR,
181 G_IO_ERROR_INVALID_ARGUMENT,
182 _("Address “%s” is invalid (need exactly one of path, tmpdir or abstract keys)"),
183 address_entry);
184 goto out;
188 ret= TRUE;
189 goto out;
191 meaningless:
192 g_set_error (error,
193 G_IO_ERROR,
194 G_IO_ERROR_INVALID_ARGUMENT,
195 _("Meaningless key/value pair combination in address entry “%s”"),
196 address_entry);
198 out:
199 g_list_free (keys);
201 return ret;
204 static gboolean
205 is_valid_nonce_tcp (const gchar *address_entry,
206 GHashTable *key_value_pairs,
207 GError **error)
209 gboolean ret;
210 GList *keys;
211 GList *l;
212 const gchar *host;
213 const gchar *port;
214 const gchar *family;
215 const gchar *nonce_file;
216 gint port_num;
217 gchar *endp;
219 ret = FALSE;
220 keys = NULL;
221 host = NULL;
222 port = NULL;
223 family = NULL;
224 nonce_file = NULL;
226 keys = g_hash_table_get_keys (key_value_pairs);
227 for (l = keys; l != NULL; l = l->next)
229 const gchar *key = l->data;
230 if (g_strcmp0 (key, "host") == 0)
231 host = g_hash_table_lookup (key_value_pairs, key);
232 else if (g_strcmp0 (key, "port") == 0)
233 port = g_hash_table_lookup (key_value_pairs, key);
234 else if (g_strcmp0 (key, "family") == 0)
235 family = g_hash_table_lookup (key_value_pairs, key);
236 else if (g_strcmp0 (key, "noncefile") == 0)
237 nonce_file = g_hash_table_lookup (key_value_pairs, key);
238 else
240 g_set_error (error,
241 G_IO_ERROR,
242 G_IO_ERROR_INVALID_ARGUMENT,
243 _("Unsupported key “%s” in address entry “%s”"),
244 key,
245 address_entry);
246 goto out;
250 if (port != NULL)
252 port_num = strtol (port, &endp, 10);
253 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
255 g_set_error (error,
256 G_IO_ERROR,
257 G_IO_ERROR_INVALID_ARGUMENT,
258 _("Error in address “%s” — the port attribute is malformed"),
259 address_entry);
260 goto out;
264 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
266 g_set_error (error,
267 G_IO_ERROR,
268 G_IO_ERROR_INVALID_ARGUMENT,
269 _("Error in address “%s” — the family attribute is malformed"),
270 address_entry);
271 goto out;
274 if (host != NULL)
276 /* TODO: validate host */
279 nonce_file = nonce_file; /* To avoid -Wunused-but-set-variable */
281 ret= TRUE;
283 out:
284 g_list_free (keys);
286 return ret;
289 static gboolean
290 is_valid_tcp (const gchar *address_entry,
291 GHashTable *key_value_pairs,
292 GError **error)
294 gboolean ret;
295 GList *keys;
296 GList *l;
297 const gchar *host;
298 const gchar *port;
299 const gchar *family;
300 gint port_num;
301 gchar *endp;
303 ret = FALSE;
304 keys = NULL;
305 host = NULL;
306 port = NULL;
307 family = NULL;
309 keys = g_hash_table_get_keys (key_value_pairs);
310 for (l = keys; l != NULL; l = l->next)
312 const gchar *key = l->data;
313 if (g_strcmp0 (key, "host") == 0)
314 host = g_hash_table_lookup (key_value_pairs, key);
315 else if (g_strcmp0 (key, "port") == 0)
316 port = g_hash_table_lookup (key_value_pairs, key);
317 else if (g_strcmp0 (key, "family") == 0)
318 family = g_hash_table_lookup (key_value_pairs, key);
319 else
321 g_set_error (error,
322 G_IO_ERROR,
323 G_IO_ERROR_INVALID_ARGUMENT,
324 _("Unsupported key “%s” in address entry “%s”"),
325 key,
326 address_entry);
327 goto out;
331 if (port != NULL)
333 port_num = strtol (port, &endp, 10);
334 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
336 g_set_error (error,
337 G_IO_ERROR,
338 G_IO_ERROR_INVALID_ARGUMENT,
339 _("Error in address “%s” — the port attribute is malformed"),
340 address_entry);
341 goto out;
345 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
347 g_set_error (error,
348 G_IO_ERROR,
349 G_IO_ERROR_INVALID_ARGUMENT,
350 _("Error in address “%s” — the family attribute is malformed"),
351 address_entry);
352 goto out;
355 if (host != NULL)
357 /* TODO: validate host */
360 ret= TRUE;
362 out:
363 g_list_free (keys);
365 return ret;
369 * g_dbus_is_supported_address:
370 * @string: A string.
371 * @error: Return location for error or %NULL.
373 * Like g_dbus_is_address() but also checks if the library supports the
374 * transports in @string and that key/value pairs for each transport
375 * are valid. See the specification of the
376 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
378 * Returns: %TRUE if @string is a valid D-Bus address that is
379 * supported by this library, %FALSE if @error is set.
381 * Since: 2.26
383 gboolean
384 g_dbus_is_supported_address (const gchar *string,
385 GError **error)
387 guint n;
388 gchar **a;
389 gboolean ret;
391 ret = FALSE;
393 g_return_val_if_fail (string != NULL, FALSE);
394 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
396 a = g_strsplit (string, ";", 0);
397 for (n = 0; a[n] != NULL; n++)
399 gchar *transport_name;
400 GHashTable *key_value_pairs;
401 gboolean supported;
403 if (!_g_dbus_address_parse_entry (a[n],
404 &transport_name,
405 &key_value_pairs,
406 error))
407 goto out;
409 supported = FALSE;
410 if (g_strcmp0 (transport_name, "unix") == 0)
411 supported = is_valid_unix (a[n], key_value_pairs, error);
412 else if (g_strcmp0 (transport_name, "tcp") == 0)
413 supported = is_valid_tcp (a[n], key_value_pairs, error);
414 else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
415 supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
416 else if (g_strcmp0 (a[n], "autolaunch:") == 0)
417 supported = TRUE;
419 g_free (transport_name);
420 g_hash_table_unref (key_value_pairs);
422 if (!supported)
423 goto out;
426 ret = TRUE;
428 out:
429 g_strfreev (a);
431 g_assert (ret || (!ret && (error == NULL || *error != NULL)));
433 return ret;
436 gboolean
437 _g_dbus_address_parse_entry (const gchar *address_entry,
438 gchar **out_transport_name,
439 GHashTable **out_key_value_pairs,
440 GError **error)
442 gboolean ret;
443 GHashTable *key_value_pairs;
444 gchar *transport_name;
445 gchar **kv_pairs;
446 const gchar *s;
447 guint n;
449 ret = FALSE;
450 kv_pairs = NULL;
451 transport_name = NULL;
452 key_value_pairs = NULL;
454 s = strchr (address_entry, ':');
455 if (s == NULL)
457 g_set_error (error,
458 G_IO_ERROR,
459 G_IO_ERROR_INVALID_ARGUMENT,
460 _("Address element “%s” does not contain a colon (:)"),
461 address_entry);
462 goto out;
465 transport_name = g_strndup (address_entry, s - address_entry);
466 key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
468 kv_pairs = g_strsplit (s + 1, ",", 0);
469 for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
471 const gchar *kv_pair = kv_pairs[n];
472 gchar *key;
473 gchar *value;
475 s = strchr (kv_pair, '=');
476 if (s == NULL)
478 g_set_error (error,
479 G_IO_ERROR,
480 G_IO_ERROR_INVALID_ARGUMENT,
481 _("Key/Value pair %d, “%s”, in address element “%s” does not contain an equal sign"),
483 kv_pair,
484 address_entry);
485 goto out;
488 key = g_uri_unescape_segment (kv_pair, s, NULL);
489 value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
490 if (key == NULL || value == NULL)
492 g_set_error (error,
493 G_IO_ERROR,
494 G_IO_ERROR_INVALID_ARGUMENT,
495 _("Error unescaping key or value in Key/Value pair %d, “%s”, in address element “%s”"),
497 kv_pair,
498 address_entry);
499 g_free (key);
500 g_free (value);
501 goto out;
503 g_hash_table_insert (key_value_pairs, key, value);
506 ret = TRUE;
508 out:
509 g_strfreev (kv_pairs);
510 if (ret)
512 if (out_transport_name != NULL)
513 *out_transport_name = transport_name;
514 else
515 g_free (transport_name);
516 if (out_key_value_pairs != NULL)
517 *out_key_value_pairs = key_value_pairs;
518 else if (key_value_pairs != NULL)
519 g_hash_table_unref (key_value_pairs);
521 else
523 g_free (transport_name);
524 if (key_value_pairs != NULL)
525 g_hash_table_unref (key_value_pairs);
527 return ret;
530 /* ---------------------------------------------------------------------------------------------------- */
532 static GIOStream *
533 g_dbus_address_try_connect_one (const gchar *address_entry,
534 gchar **out_guid,
535 GCancellable *cancellable,
536 GError **error);
538 /* TODO: Declare an extension point called GDBusTransport (or similar)
539 * and move code below to extensions implementing said extension
540 * point. That way we can implement a D-Bus transport over X11 without
541 * making libgio link to libX11...
543 static GIOStream *
544 g_dbus_address_connect (const gchar *address_entry,
545 const gchar *transport_name,
546 GHashTable *key_value_pairs,
547 GCancellable *cancellable,
548 GError **error)
550 GIOStream *ret;
551 GSocketConnectable *connectable;
552 const gchar *nonce_file;
554 connectable = NULL;
555 ret = NULL;
556 nonce_file = NULL;
558 if (FALSE)
561 #ifdef G_OS_UNIX
562 else if (g_strcmp0 (transport_name, "unix") == 0)
564 const gchar *path;
565 const gchar *abstract;
566 path = g_hash_table_lookup (key_value_pairs, "path");
567 abstract = g_hash_table_lookup (key_value_pairs, "abstract");
568 if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
570 g_set_error (error,
571 G_IO_ERROR,
572 G_IO_ERROR_INVALID_ARGUMENT,
573 _("Error in address “%s” — the unix transport requires exactly one of the "
574 "keys “path” or “abstract” to be set"),
575 address_entry);
577 else if (path != NULL)
579 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
581 else if (abstract != NULL)
583 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
585 G_UNIX_SOCKET_ADDRESS_ABSTRACT));
587 else
589 g_assert_not_reached ();
592 #endif
593 else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
595 const gchar *s;
596 const gchar *host;
597 glong port;
598 gchar *endp;
599 gboolean is_nonce;
601 is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
603 host = g_hash_table_lookup (key_value_pairs, "host");
604 if (host == NULL)
606 g_set_error (error,
607 G_IO_ERROR,
608 G_IO_ERROR_INVALID_ARGUMENT,
609 _("Error in address “%s” — the host attribute is missing or malformed"),
610 address_entry);
611 goto out;
614 s = g_hash_table_lookup (key_value_pairs, "port");
615 if (s == NULL)
616 s = "0";
617 port = strtol (s, &endp, 10);
618 if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
620 g_set_error (error,
621 G_IO_ERROR,
622 G_IO_ERROR_INVALID_ARGUMENT,
623 _("Error in address “%s” — the port attribute is missing or malformed"),
624 address_entry);
625 goto out;
629 if (is_nonce)
631 nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
632 if (nonce_file == NULL)
634 g_set_error (error,
635 G_IO_ERROR,
636 G_IO_ERROR_INVALID_ARGUMENT,
637 _("Error in address “%s” — the noncefile attribute is missing or malformed"),
638 address_entry);
639 goto out;
643 /* TODO: deal with family key/value-pair */
644 connectable = g_network_address_new (host, port);
646 else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
648 gchar *autolaunch_address;
649 autolaunch_address = get_session_address_dbus_launch (error);
650 if (autolaunch_address != NULL)
652 ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
653 g_free (autolaunch_address);
654 goto out;
656 else
658 g_prefix_error (error, _("Error auto-launching: "));
661 else
663 g_set_error (error,
664 G_IO_ERROR,
665 G_IO_ERROR_INVALID_ARGUMENT,
666 _("Unknown or unsupported transport “%s” for address “%s”"),
667 transport_name,
668 address_entry);
671 if (connectable != NULL)
673 GSocketClient *client;
674 GSocketConnection *connection;
676 g_assert (ret == NULL);
677 client = g_socket_client_new ();
678 connection = g_socket_client_connect (client,
679 connectable,
680 cancellable,
681 error);
682 g_object_unref (connectable);
683 g_object_unref (client);
684 if (connection == NULL)
685 goto out;
687 ret = G_IO_STREAM (connection);
689 if (nonce_file != NULL)
691 gchar nonce_contents[16 + 1];
692 size_t num_bytes_read;
693 FILE *f;
695 /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
696 f = fopen (nonce_file, "rb");
697 if (f == NULL)
699 g_set_error (error,
700 G_IO_ERROR,
701 G_IO_ERROR_INVALID_ARGUMENT,
702 _("Error opening nonce file “%s”: %s"),
703 nonce_file,
704 g_strerror (errno));
705 g_object_unref (ret);
706 ret = NULL;
707 goto out;
709 num_bytes_read = fread (nonce_contents,
710 sizeof (gchar),
711 16 + 1,
713 if (num_bytes_read != 16)
715 if (num_bytes_read == 0)
717 g_set_error (error,
718 G_IO_ERROR,
719 G_IO_ERROR_INVALID_ARGUMENT,
720 _("Error reading from nonce file “%s”: %s"),
721 nonce_file,
722 g_strerror (errno));
724 else
726 g_set_error (error,
727 G_IO_ERROR,
728 G_IO_ERROR_INVALID_ARGUMENT,
729 _("Error reading from nonce file “%s”, expected 16 bytes, got %d"),
730 nonce_file,
731 (gint) num_bytes_read);
733 g_object_unref (ret);
734 ret = NULL;
735 fclose (f);
736 goto out;
738 fclose (f);
740 if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
741 nonce_contents,
743 NULL,
744 cancellable,
745 error))
747 g_prefix_error (error, _("Error writing contents of nonce file “%s” to stream:"), nonce_file);
748 g_object_unref (ret);
749 ret = NULL;
750 goto out;
755 out:
757 return ret;
760 static GIOStream *
761 g_dbus_address_try_connect_one (const gchar *address_entry,
762 gchar **out_guid,
763 GCancellable *cancellable,
764 GError **error)
766 GIOStream *ret;
767 GHashTable *key_value_pairs;
768 gchar *transport_name;
769 const gchar *guid;
771 ret = NULL;
772 transport_name = NULL;
773 key_value_pairs = NULL;
775 if (!_g_dbus_address_parse_entry (address_entry,
776 &transport_name,
777 &key_value_pairs,
778 error))
779 goto out;
781 ret = g_dbus_address_connect (address_entry,
782 transport_name,
783 key_value_pairs,
784 cancellable,
785 error);
786 if (ret == NULL)
787 goto out;
789 guid = g_hash_table_lookup (key_value_pairs, "guid");
790 if (guid != NULL && out_guid != NULL)
791 *out_guid = g_strdup (guid);
793 out:
794 g_free (transport_name);
795 if (key_value_pairs != NULL)
796 g_hash_table_unref (key_value_pairs);
797 return ret;
801 /* ---------------------------------------------------------------------------------------------------- */
803 typedef struct {
804 gchar *address;
805 gchar *guid;
806 } GetStreamData;
808 static void
809 get_stream_data_free (GetStreamData *data)
811 g_free (data->address);
812 g_free (data->guid);
813 g_free (data);
816 static void
817 get_stream_thread_func (GTask *task,
818 gpointer source_object,
819 gpointer task_data,
820 GCancellable *cancellable)
822 GetStreamData *data = task_data;
823 GIOStream *stream;
824 GError *error = NULL;
826 stream = g_dbus_address_get_stream_sync (data->address,
827 &data->guid,
828 cancellable,
829 &error);
830 if (stream)
831 g_task_return_pointer (task, stream, g_object_unref);
832 else
833 g_task_return_error (task, error);
837 * g_dbus_address_get_stream:
838 * @address: A valid D-Bus address.
839 * @cancellable: (nullable): A #GCancellable or %NULL.
840 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
841 * @user_data: Data to pass to @callback.
843 * Asynchronously connects to an endpoint specified by @address and
844 * sets up the connection so it is in a state to run the client-side
845 * of the D-Bus authentication conversation. @address must be in the
846 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
848 * When the operation is finished, @callback will be invoked. You can
849 * then call g_dbus_address_get_stream_finish() to get the result of
850 * the operation.
852 * This is an asynchronous failable function. See
853 * g_dbus_address_get_stream_sync() for the synchronous version.
855 * Since: 2.26
857 void
858 g_dbus_address_get_stream (const gchar *address,
859 GCancellable *cancellable,
860 GAsyncReadyCallback callback,
861 gpointer user_data)
863 GTask *task;
864 GetStreamData *data;
866 g_return_if_fail (address != NULL);
868 data = g_new0 (GetStreamData, 1);
869 data->address = g_strdup (address);
871 task = g_task_new (NULL, cancellable, callback, user_data);
872 g_task_set_source_tag (task, g_dbus_address_get_stream);
873 g_task_set_task_data (task, data, (GDestroyNotify) get_stream_data_free);
874 g_task_run_in_thread (task, get_stream_thread_func);
875 g_object_unref (task);
879 * g_dbus_address_get_stream_finish:
880 * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
881 * @out_guid: (optional) (out): %NULL or return location to store the GUID extracted from @address, if any.
882 * @error: Return location for error or %NULL.
884 * Finishes an operation started with g_dbus_address_get_stream().
886 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
888 * Since: 2.26
890 GIOStream *
891 g_dbus_address_get_stream_finish (GAsyncResult *res,
892 gchar **out_guid,
893 GError **error)
895 GTask *task;
896 GetStreamData *data;
897 GIOStream *ret;
899 g_return_val_if_fail (g_task_is_valid (res, NULL), NULL);
900 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
902 task = G_TASK (res);
903 ret = g_task_propagate_pointer (task, error);
905 if (ret != NULL && out_guid != NULL)
907 data = g_task_get_task_data (task);
908 *out_guid = data->guid;
909 data->guid = NULL;
912 return ret;
916 * g_dbus_address_get_stream_sync:
917 * @address: A valid D-Bus address.
918 * @out_guid: (optional) (out): %NULL or return location to store the GUID extracted from @address, if any.
919 * @cancellable: (nullable): A #GCancellable or %NULL.
920 * @error: Return location for error or %NULL.
922 * Synchronously connects to an endpoint specified by @address and
923 * sets up the connection so it is in a state to run the client-side
924 * of the D-Bus authentication conversation. @address must be in the
925 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
927 * This is a synchronous failable function. See
928 * g_dbus_address_get_stream() for the asynchronous version.
930 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
932 * Since: 2.26
934 GIOStream *
935 g_dbus_address_get_stream_sync (const gchar *address,
936 gchar **out_guid,
937 GCancellable *cancellable,
938 GError **error)
940 GIOStream *ret;
941 gchar **addr_array;
942 guint n;
943 GError *last_error;
945 g_return_val_if_fail (address != NULL, NULL);
946 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
948 ret = NULL;
949 last_error = NULL;
951 addr_array = g_strsplit (address, ";", 0);
952 if (addr_array != NULL && addr_array[0] == NULL)
954 last_error = g_error_new_literal (G_IO_ERROR,
955 G_IO_ERROR_INVALID_ARGUMENT,
956 _("The given address is empty"));
957 goto out;
960 for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
962 const gchar *addr = addr_array[n];
963 GError *this_error;
965 this_error = NULL;
966 ret = g_dbus_address_try_connect_one (addr,
967 out_guid,
968 cancellable,
969 &this_error);
970 if (ret != NULL)
972 goto out;
974 else
976 g_assert (this_error != NULL);
977 if (last_error != NULL)
978 g_error_free (last_error);
979 last_error = this_error;
983 out:
984 if (ret != NULL)
986 if (last_error != NULL)
987 g_error_free (last_error);
989 else
991 g_assert (last_error != NULL);
992 g_propagate_error (error, last_error);
995 g_strfreev (addr_array);
996 return ret;
999 /* ---------------------------------------------------------------------------------------------------- */
1002 * Return the address of XDG_RUNTIME_DIR/bus if it exists, belongs to
1003 * us, and is a socket, and we are on Unix.
1005 static gchar *
1006 get_session_address_xdg (void)
1008 #ifdef G_OS_UNIX
1009 gchar *ret = NULL;
1010 gchar *bus;
1011 gchar *tmp;
1012 GStatBuf buf;
1014 bus = g_build_filename (g_get_user_runtime_dir (), "bus", NULL);
1016 /* if ENOENT, EPERM, etc., quietly don't use it */
1017 if (g_stat (bus, &buf) < 0)
1018 goto out;
1020 /* if it isn't ours, we have incorrectly inherited someone else's
1021 * XDG_RUNTIME_DIR; silently don't use it
1023 if (buf.st_uid != geteuid ())
1024 goto out;
1026 /* if it isn't a socket, silently don't use it */
1027 if ((buf.st_mode & S_IFMT) != S_IFSOCK)
1028 goto out;
1030 tmp = g_dbus_address_escape_value (bus);
1031 ret = g_strconcat ("unix:path=", tmp, NULL);
1032 g_free (tmp);
1034 out:
1035 g_free (bus);
1036 return ret;
1037 #else
1038 return NULL;
1039 #endif
1042 /* ---------------------------------------------------------------------------------------------------- */
1044 #ifdef G_OS_UNIX
1045 static gchar *
1046 get_session_address_dbus_launch (GError **error)
1048 gchar *ret;
1049 gchar *machine_id;
1050 gchar *command_line;
1051 gchar *launch_stdout;
1052 gchar *launch_stderr;
1053 gint exit_status;
1054 gchar *old_dbus_verbose;
1055 gboolean restore_dbus_verbose;
1057 ret = NULL;
1058 machine_id = NULL;
1059 command_line = NULL;
1060 launch_stdout = NULL;
1061 launch_stderr = NULL;
1062 restore_dbus_verbose = FALSE;
1063 old_dbus_verbose = NULL;
1065 /* Don't run binaries as root if we're setuid. */
1066 if (GLIB_PRIVATE_CALL (g_check_setuid) ())
1068 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1069 _("Cannot spawn a message bus when setuid"));
1070 goto out;
1073 machine_id = _g_dbus_get_machine_id (error);
1074 if (machine_id == NULL)
1076 g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1077 goto out;
1080 if (g_getenv ("DISPLAY") == NULL)
1082 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1083 _("Cannot autolaunch D-Bus without X11 $DISPLAY"));
1084 goto out;
1087 /* We're using private libdbus facilities here. When everything
1088 * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1089 * X11 property is correctly documented right now) we should
1090 * consider using the spec instead of dbus-launch.
1092 * --autolaunch=MACHINEID
1093 * This option implies that dbus-launch should scan for a previ‐
1094 * ously-started session and reuse the values found there. If no
1095 * session is found, it will start a new session. The --exit-with-
1096 * session option is implied if --autolaunch is given. This option
1097 * is for the exclusive use of libdbus, you do not want to use it
1098 * manually. It may change in the future.
1101 /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1102 command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1104 if (G_UNLIKELY (_g_dbus_debug_address ()))
1106 _g_dbus_debug_print_lock ();
1107 g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
1108 old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1109 restore_dbus_verbose = TRUE;
1110 g_setenv ("DBUS_VERBOSE", "1", TRUE);
1111 _g_dbus_debug_print_unlock ();
1114 if (!g_spawn_command_line_sync (command_line,
1115 &launch_stdout,
1116 &launch_stderr,
1117 &exit_status,
1118 error))
1120 goto out;
1123 if (!g_spawn_check_exit_status (exit_status, error))
1125 g_prefix_error (error, _("Error spawning command line “%s”: "), command_line);
1126 goto out;
1129 /* From the dbus-launch(1) man page:
1131 * --binary-syntax Write to stdout a nul-terminated bus address,
1132 * then the bus PID as a binary integer of size sizeof(pid_t),
1133 * then the bus X window ID as a binary integer of size
1134 * sizeof(long). Integers are in the machine's byte order, not
1135 * network byte order or any other canonical byte order.
1137 ret = g_strdup (launch_stdout);
1139 out:
1140 if (G_UNLIKELY (_g_dbus_debug_address ()))
1142 gchar *s;
1143 _g_dbus_debug_print_lock ();
1144 g_print ("GDBus-debug:Address: dbus-launch output:");
1145 if (launch_stdout != NULL)
1147 s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1148 g_print ("\n%s", s);
1149 g_free (s);
1151 else
1153 g_print (" (none)\n");
1155 g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1156 if (launch_stderr != NULL)
1157 g_print ("\n%s", launch_stderr);
1158 else
1159 g_print (" (none)\n");
1160 _g_dbus_debug_print_unlock ();
1163 g_free (machine_id);
1164 g_free (command_line);
1165 g_free (launch_stdout);
1166 g_free (launch_stderr);
1167 if (G_UNLIKELY (restore_dbus_verbose))
1169 if (old_dbus_verbose != NULL)
1170 g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1171 else
1172 g_unsetenv ("DBUS_VERBOSE");
1174 g_free (old_dbus_verbose);
1175 return ret;
1178 /* end of G_OS_UNIX case */
1179 #elif defined(G_OS_WIN32)
1181 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1182 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1183 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1184 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1186 static void
1187 release_mutex (HANDLE mutex)
1189 ReleaseMutex (mutex);
1190 CloseHandle (mutex);
1193 static HANDLE
1194 acquire_mutex (const char *mutexname)
1196 HANDLE mutex;
1197 DWORD res;
1199 mutex = CreateMutexA (NULL, FALSE, mutexname);
1200 if (!mutex)
1201 return 0;
1203 res = WaitForSingleObject (mutex, INFINITE);
1204 switch (res)
1206 case WAIT_ABANDONED:
1207 release_mutex (mutex);
1208 return 0;
1209 case WAIT_FAILED:
1210 case WAIT_TIMEOUT:
1211 return 0;
1214 return mutex;
1217 static gboolean
1218 is_mutex_owned (const char *mutexname)
1220 HANDLE mutex;
1221 gboolean res = FALSE;
1223 mutex = CreateMutexA (NULL, FALSE, mutexname);
1224 if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1225 res = TRUE;
1226 else
1227 ReleaseMutex (mutex);
1228 CloseHandle (mutex);
1230 return res;
1233 static char *
1234 read_shm (const char *shm_name)
1236 HANDLE shared_mem;
1237 char *shared_data;
1238 char *res;
1239 int i;
1241 res = NULL;
1243 for (i = 0; i < 20; i++)
1245 shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1246 if (shared_mem != 0)
1247 break;
1248 Sleep (100);
1251 if (shared_mem != 0)
1253 shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1254 if (shared_data != NULL)
1256 res = g_strdup (shared_data);
1257 UnmapViewOfFile (shared_data);
1259 CloseHandle (shared_mem);
1262 return res;
1265 static HANDLE
1266 set_shm (const char *shm_name, const char *value)
1268 HANDLE shared_mem;
1269 char *shared_data;
1271 shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1272 0, strlen (value) + 1, shm_name);
1273 if (shared_mem == 0)
1274 return 0;
1276 shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1277 if (shared_data == NULL)
1278 return 0;
1280 strcpy (shared_data, value);
1282 UnmapViewOfFile (shared_data);
1284 return shared_mem;
1287 /* These keep state between publish_session_bus and unpublish_session_bus */
1288 static HANDLE published_daemon_mutex;
1289 static HANDLE published_shared_mem;
1291 static gboolean
1292 publish_session_bus (const char *address)
1294 HANDLE init_mutex;
1296 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1298 published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1299 if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1301 release_mutex (init_mutex);
1302 CloseHandle (published_daemon_mutex);
1303 published_daemon_mutex = NULL;
1304 return FALSE;
1307 published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1308 if (!published_shared_mem)
1310 release_mutex (init_mutex);
1311 CloseHandle (published_daemon_mutex);
1312 published_daemon_mutex = NULL;
1313 return FALSE;
1316 release_mutex (init_mutex);
1317 return TRUE;
1320 static void
1321 unpublish_session_bus (void)
1323 HANDLE init_mutex;
1325 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1327 CloseHandle (published_shared_mem);
1328 published_shared_mem = NULL;
1330 release_mutex (published_daemon_mutex);
1331 published_daemon_mutex = NULL;
1333 release_mutex (init_mutex);
1336 static void
1337 wait_console_window (void)
1339 FILE *console = fopen ("CONOUT$", "w");
1341 SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1342 fprintf (console, _("(Type any character to close this window)\n"));
1343 fflush (console);
1344 _getch ();
1347 static void
1348 open_console_window (void)
1350 if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1351 (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1353 if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1354 freopen ("CONOUT$", "w", stdout);
1356 if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1357 freopen ("CONOUT$", "w", stderr);
1359 SetConsoleTitleW (L"gdbus-daemon debug output.");
1361 atexit (wait_console_window);
1365 static void
1366 idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1368 GMainLoop *loop = user_data;
1369 g_main_loop_quit (loop);
1372 /* Satisfies STARTF_FORCEONFEEDBACK */
1373 static void
1374 turn_off_the_starting_cursor (void)
1376 MSG msg;
1377 BOOL bRet;
1379 PostQuitMessage (0);
1381 while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0)
1383 if (bRet == -1)
1384 continue;
1386 TranslateMessage (&msg);
1387 DispatchMessage (&msg);
1391 __declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
1393 __declspec(dllexport) void CALLBACK
1394 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1396 GDBusDaemon *daemon;
1397 GMainLoop *loop;
1398 const char *address;
1399 GError *error = NULL;
1401 turn_off_the_starting_cursor ();
1403 if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1404 open_console_window ();
1406 loop = g_main_loop_new (NULL, FALSE);
1408 address = "nonce-tcp:";
1409 daemon = _g_dbus_daemon_new (address, NULL, &error);
1410 if (daemon == NULL)
1412 g_printerr ("Can't init bus: %s\n", error->message);
1413 g_error_free (error);
1414 return;
1417 g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1419 if (publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1421 g_main_loop_run (loop);
1423 unpublish_session_bus ();
1426 g_main_loop_unref (loop);
1427 g_object_unref (daemon);
1430 static gchar *
1431 get_session_address_dbus_launch (GError **error)
1433 HANDLE autolaunch_mutex, init_mutex;
1434 char *address = NULL;
1435 wchar_t gio_path[MAX_PATH+1+200];
1437 autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1439 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1441 if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1442 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1444 release_mutex (init_mutex);
1446 if (address == NULL)
1448 gio_path[MAX_PATH] = 0;
1449 if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1451 PROCESS_INFORMATION pi = { 0 };
1452 STARTUPINFOW si = { 0 };
1453 BOOL res;
1454 wchar_t gio_path_short[MAX_PATH];
1455 wchar_t rundll_path[MAX_PATH*2];
1456 wchar_t args[MAX_PATH*4];
1458 GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1460 GetWindowsDirectoryW (rundll_path, MAX_PATH);
1461 wcscat (rundll_path, L"\\rundll32.exe");
1462 if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1464 GetSystemDirectoryW (rundll_path, MAX_PATH);
1465 wcscat (rundll_path, L"\\rundll32.exe");
1468 wcscpy (args, L"\"");
1469 wcscat (args, rundll_path);
1470 wcscat (args, L"\" ");
1471 wcscat (args, gio_path_short);
1472 #if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
1473 wcscat (args, L",g_win32_run_session_bus");
1474 #elif defined (_MSC_VER)
1475 wcscat (args, L",_g_win32_run_session_bus@16");
1476 #else
1477 wcscat (args, L",g_win32_run_session_bus@16");
1478 #endif
1480 res = CreateProcessW (rundll_path, args,
1481 0, 0, FALSE,
1482 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1483 0, NULL /* TODO: Should be root */,
1484 &si, &pi);
1485 if (res)
1486 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1490 release_mutex (autolaunch_mutex);
1492 if (address == NULL)
1493 g_set_error (error,
1494 G_IO_ERROR,
1495 G_IO_ERROR_FAILED,
1496 _("Session dbus not running, and autolaunch failed"));
1498 return address;
1500 #else /* neither G_OS_UNIX nor G_OS_WIN32 */
1501 static gchar *
1502 get_session_address_dbus_launch (GError **error)
1504 g_set_error (error,
1505 G_IO_ERROR,
1506 G_IO_ERROR_FAILED,
1507 _("Cannot determine session bus address (not implemented for this OS)"));
1508 return NULL;
1510 #endif /* neither G_OS_UNIX nor G_OS_WIN32 */
1512 /* ---------------------------------------------------------------------------------------------------- */
1514 static gchar *
1515 get_session_address_platform_specific (GError **error)
1517 gchar *ret;
1519 /* Use XDG_RUNTIME_DIR/bus if it exists and is suitable. This is appropriate
1520 * for systems using the "a session is a user-session" model described in
1521 * <http://lists.freedesktop.org/archives/dbus/2015-January/016522.html>,
1522 * and implemented in dbus >= 1.9.14 and sd-bus.
1524 * On systems following the more traditional "a session is a login-session"
1525 * model, this will fail and we'll fall through to X11 autolaunching
1526 * (dbus-launch) below.
1528 ret = get_session_address_xdg ();
1530 if (ret != NULL)
1531 return ret;
1533 /* TODO (#694472): try launchd on OS X, like
1534 * _dbus_lookup_session_address_launchd() does, since
1535 * 'dbus-launch --autolaunch' probably won't work there
1538 /* As a last resort, try the "autolaunch:" transport. On Unix this means
1539 * X11 autolaunching; on Windows this means a different autolaunching
1540 * mechanism based on shared memory.
1542 return get_session_address_dbus_launch (error);
1545 /* ---------------------------------------------------------------------------------------------------- */
1548 * g_dbus_address_get_for_bus_sync:
1549 * @bus_type: a #GBusType
1550 * @cancellable: (nullable): a #GCancellable or %NULL
1551 * @error: return location for error or %NULL
1553 * Synchronously looks up the D-Bus address for the well-known message
1554 * bus instance specified by @bus_type. This may involve using various
1555 * platform specific mechanisms.
1557 * The returned address will be in the
1558 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
1560 * Returns: a valid D-Bus address string for @bus_type or %NULL if
1561 * @error is set
1563 * Since: 2.26
1565 gchar *
1566 g_dbus_address_get_for_bus_sync (GBusType bus_type,
1567 GCancellable *cancellable,
1568 GError **error)
1570 gchar *ret, *s = NULL;
1571 const gchar *starter_bus;
1572 GError *local_error;
1574 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1576 ret = NULL;
1577 local_error = NULL;
1579 if (G_UNLIKELY (_g_dbus_debug_address ()))
1581 guint n;
1582 _g_dbus_debug_print_lock ();
1583 s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1584 g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1586 g_free (s);
1587 for (n = 0; n < 3; n++)
1589 const gchar *k;
1590 const gchar *v;
1591 switch (n)
1593 case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1594 case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1595 case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1596 default: g_assert_not_reached ();
1598 v = g_getenv (k);
1599 g_print ("GDBus-debug:Address: env var %s", k);
1600 if (v != NULL)
1601 g_print ("='%s'\n", v);
1602 else
1603 g_print (" is not set\n");
1605 _g_dbus_debug_print_unlock ();
1608 switch (bus_type)
1610 case G_BUS_TYPE_SYSTEM:
1611 ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1612 if (ret == NULL)
1614 ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1616 break;
1618 case G_BUS_TYPE_SESSION:
1619 ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1620 if (ret == NULL)
1622 ret = get_session_address_platform_specific (&local_error);
1624 break;
1626 case G_BUS_TYPE_STARTER:
1627 starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1628 if (g_strcmp0 (starter_bus, "session") == 0)
1630 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1631 goto out;
1633 else if (g_strcmp0 (starter_bus, "system") == 0)
1635 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1636 goto out;
1638 else
1640 if (starter_bus != NULL)
1642 g_set_error (&local_error,
1643 G_IO_ERROR,
1644 G_IO_ERROR_FAILED,
1645 _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1646 " — unknown value “%s”"),
1647 starter_bus);
1649 else
1651 g_set_error_literal (&local_error,
1652 G_IO_ERROR,
1653 G_IO_ERROR_FAILED,
1654 _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1655 "variable is not set"));
1658 break;
1660 default:
1661 g_set_error (&local_error,
1662 G_IO_ERROR,
1663 G_IO_ERROR_FAILED,
1664 _("Unknown bus type %d"),
1665 bus_type);
1666 break;
1669 out:
1670 if (G_UNLIKELY (_g_dbus_debug_address ()))
1672 _g_dbus_debug_print_lock ();
1673 s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1674 if (ret != NULL)
1676 g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1677 ret, s);
1679 else
1681 g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1682 s, local_error ? local_error->message : "");
1684 g_free (s);
1685 _g_dbus_debug_print_unlock ();
1688 if (local_error != NULL)
1689 g_propagate_error (error, local_error);
1691 return ret;
1695 * g_dbus_address_escape_value:
1696 * @string: an unescaped string to be included in a D-Bus address
1697 * as the value in a key-value pair
1699 * Escape @string so it can appear in a D-Bus address as the value
1700 * part of a key-value pair.
1702 * For instance, if @string is "/run/bus-for-:0",
1703 * this function would return "/run/bus-for-%3A0",
1704 * which could be used in a D-Bus address like
1705 * "unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0".
1707 * Returns: (transfer full): a copy of @string with all
1708 * non-optionally-escaped bytes escaped
1710 * Since: 2.36
1712 gchar *
1713 g_dbus_address_escape_value (const gchar *string)
1715 GString *s;
1716 gsize i;
1718 g_return_val_if_fail (string != NULL, NULL);
1720 /* There will often not be anything needing escaping at all. */
1721 s = g_string_sized_new (strlen (string));
1723 /* D-Bus address escaping is mostly the same as URI escaping... */
1724 g_string_append_uri_escaped (s, string, "\\/", FALSE);
1726 /* ... but '~' is an unreserved character in URIs, but a
1727 * non-optionally-escaped character in D-Bus addresses. */
1728 for (i = 0; i < s->len; i++)
1730 if (G_UNLIKELY (s->str[i] == '~'))
1732 s->str[i] = '%';
1733 g_string_insert (s, i + 1, "7E");
1734 i += 2;
1738 return g_string_free (s, FALSE);