meson: work around meson not passing on the threads dependency when link_with is...
[glib.git] / gio / gdbusaddress.c
blobfaee80087ad206bcdbc9879712d5ea40b82264f3
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.1 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;
694 int errsv;
696 /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
697 f = fopen (nonce_file, "rb");
698 errsv = errno;
699 if (f == NULL)
701 g_set_error (error,
702 G_IO_ERROR,
703 G_IO_ERROR_INVALID_ARGUMENT,
704 _("Error opening nonce file “%s”: %s"),
705 nonce_file,
706 g_strerror (errsv));
707 g_object_unref (ret);
708 ret = NULL;
709 goto out;
711 num_bytes_read = fread (nonce_contents,
712 sizeof (gchar),
713 16 + 1,
715 errsv = errno;
716 if (num_bytes_read != 16)
718 if (num_bytes_read == 0)
720 g_set_error (error,
721 G_IO_ERROR,
722 G_IO_ERROR_INVALID_ARGUMENT,
723 _("Error reading from nonce file “%s”: %s"),
724 nonce_file,
725 g_strerror (errsv));
727 else
729 g_set_error (error,
730 G_IO_ERROR,
731 G_IO_ERROR_INVALID_ARGUMENT,
732 _("Error reading from nonce file “%s”, expected 16 bytes, got %d"),
733 nonce_file,
734 (gint) num_bytes_read);
736 g_object_unref (ret);
737 ret = NULL;
738 fclose (f);
739 goto out;
741 fclose (f);
743 if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
744 nonce_contents,
746 NULL,
747 cancellable,
748 error))
750 g_prefix_error (error, _("Error writing contents of nonce file “%s” to stream:"), nonce_file);
751 g_object_unref (ret);
752 ret = NULL;
753 goto out;
758 out:
760 return ret;
763 static GIOStream *
764 g_dbus_address_try_connect_one (const gchar *address_entry,
765 gchar **out_guid,
766 GCancellable *cancellable,
767 GError **error)
769 GIOStream *ret;
770 GHashTable *key_value_pairs;
771 gchar *transport_name;
772 const gchar *guid;
774 ret = NULL;
775 transport_name = NULL;
776 key_value_pairs = NULL;
778 if (!_g_dbus_address_parse_entry (address_entry,
779 &transport_name,
780 &key_value_pairs,
781 error))
782 goto out;
784 ret = g_dbus_address_connect (address_entry,
785 transport_name,
786 key_value_pairs,
787 cancellable,
788 error);
789 if (ret == NULL)
790 goto out;
792 guid = g_hash_table_lookup (key_value_pairs, "guid");
793 if (guid != NULL && out_guid != NULL)
794 *out_guid = g_strdup (guid);
796 out:
797 g_free (transport_name);
798 if (key_value_pairs != NULL)
799 g_hash_table_unref (key_value_pairs);
800 return ret;
804 /* ---------------------------------------------------------------------------------------------------- */
806 typedef struct {
807 gchar *address;
808 gchar *guid;
809 } GetStreamData;
811 static void
812 get_stream_data_free (GetStreamData *data)
814 g_free (data->address);
815 g_free (data->guid);
816 g_free (data);
819 static void
820 get_stream_thread_func (GTask *task,
821 gpointer source_object,
822 gpointer task_data,
823 GCancellable *cancellable)
825 GetStreamData *data = task_data;
826 GIOStream *stream;
827 GError *error = NULL;
829 stream = g_dbus_address_get_stream_sync (data->address,
830 &data->guid,
831 cancellable,
832 &error);
833 if (stream)
834 g_task_return_pointer (task, stream, g_object_unref);
835 else
836 g_task_return_error (task, error);
840 * g_dbus_address_get_stream:
841 * @address: A valid D-Bus address.
842 * @cancellable: (nullable): A #GCancellable or %NULL.
843 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
844 * @user_data: Data to pass to @callback.
846 * Asynchronously connects to an endpoint specified by @address and
847 * sets up the connection so it is in a state to run the client-side
848 * of the D-Bus authentication conversation. @address must be in the
849 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
851 * When the operation is finished, @callback will be invoked. You can
852 * then call g_dbus_address_get_stream_finish() to get the result of
853 * the operation.
855 * This is an asynchronous failable function. See
856 * g_dbus_address_get_stream_sync() for the synchronous version.
858 * Since: 2.26
860 void
861 g_dbus_address_get_stream (const gchar *address,
862 GCancellable *cancellable,
863 GAsyncReadyCallback callback,
864 gpointer user_data)
866 GTask *task;
867 GetStreamData *data;
869 g_return_if_fail (address != NULL);
871 data = g_new0 (GetStreamData, 1);
872 data->address = g_strdup (address);
874 task = g_task_new (NULL, cancellable, callback, user_data);
875 g_task_set_source_tag (task, g_dbus_address_get_stream);
876 g_task_set_task_data (task, data, (GDestroyNotify) get_stream_data_free);
877 g_task_run_in_thread (task, get_stream_thread_func);
878 g_object_unref (task);
882 * g_dbus_address_get_stream_finish:
883 * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
884 * @out_guid: (optional) (out): %NULL or return location to store the GUID extracted from @address, if any.
885 * @error: Return location for error or %NULL.
887 * Finishes an operation started with g_dbus_address_get_stream().
889 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
891 * Since: 2.26
893 GIOStream *
894 g_dbus_address_get_stream_finish (GAsyncResult *res,
895 gchar **out_guid,
896 GError **error)
898 GTask *task;
899 GetStreamData *data;
900 GIOStream *ret;
902 g_return_val_if_fail (g_task_is_valid (res, NULL), NULL);
903 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
905 task = G_TASK (res);
906 ret = g_task_propagate_pointer (task, error);
908 if (ret != NULL && out_guid != NULL)
910 data = g_task_get_task_data (task);
911 *out_guid = data->guid;
912 data->guid = NULL;
915 return ret;
919 * g_dbus_address_get_stream_sync:
920 * @address: A valid D-Bus address.
921 * @out_guid: (optional) (out): %NULL or return location to store the GUID extracted from @address, if any.
922 * @cancellable: (nullable): A #GCancellable or %NULL.
923 * @error: Return location for error or %NULL.
925 * Synchronously connects to an endpoint specified by @address and
926 * sets up the connection so it is in a state to run the client-side
927 * of the D-Bus authentication conversation. @address must be in the
928 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
930 * This is a synchronous failable function. See
931 * g_dbus_address_get_stream() for the asynchronous version.
933 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
935 * Since: 2.26
937 GIOStream *
938 g_dbus_address_get_stream_sync (const gchar *address,
939 gchar **out_guid,
940 GCancellable *cancellable,
941 GError **error)
943 GIOStream *ret;
944 gchar **addr_array;
945 guint n;
946 GError *last_error;
948 g_return_val_if_fail (address != NULL, NULL);
949 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
951 ret = NULL;
952 last_error = NULL;
954 addr_array = g_strsplit (address, ";", 0);
955 if (addr_array != NULL && addr_array[0] == NULL)
957 last_error = g_error_new_literal (G_IO_ERROR,
958 G_IO_ERROR_INVALID_ARGUMENT,
959 _("The given address is empty"));
960 goto out;
963 for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
965 const gchar *addr = addr_array[n];
966 GError *this_error;
968 this_error = NULL;
969 ret = g_dbus_address_try_connect_one (addr,
970 out_guid,
971 cancellable,
972 &this_error);
973 if (ret != NULL)
975 goto out;
977 else
979 g_assert (this_error != NULL);
980 if (last_error != NULL)
981 g_error_free (last_error);
982 last_error = this_error;
986 out:
987 if (ret != NULL)
989 if (last_error != NULL)
990 g_error_free (last_error);
992 else
994 g_assert (last_error != NULL);
995 g_propagate_error (error, last_error);
998 g_strfreev (addr_array);
999 return ret;
1002 /* ---------------------------------------------------------------------------------------------------- */
1005 * Return the address of XDG_RUNTIME_DIR/bus if it exists, belongs to
1006 * us, and is a socket, and we are on Unix.
1008 static gchar *
1009 get_session_address_xdg (void)
1011 #ifdef G_OS_UNIX
1012 gchar *ret = NULL;
1013 gchar *bus;
1014 gchar *tmp;
1015 GStatBuf buf;
1017 bus = g_build_filename (g_get_user_runtime_dir (), "bus", NULL);
1019 /* if ENOENT, EPERM, etc., quietly don't use it */
1020 if (g_stat (bus, &buf) < 0)
1021 goto out;
1023 /* if it isn't ours, we have incorrectly inherited someone else's
1024 * XDG_RUNTIME_DIR; silently don't use it
1026 if (buf.st_uid != geteuid ())
1027 goto out;
1029 /* if it isn't a socket, silently don't use it */
1030 if ((buf.st_mode & S_IFMT) != S_IFSOCK)
1031 goto out;
1033 tmp = g_dbus_address_escape_value (bus);
1034 ret = g_strconcat ("unix:path=", tmp, NULL);
1035 g_free (tmp);
1037 out:
1038 g_free (bus);
1039 return ret;
1040 #else
1041 return NULL;
1042 #endif
1045 /* ---------------------------------------------------------------------------------------------------- */
1047 #ifdef G_OS_UNIX
1048 static gchar *
1049 get_session_address_dbus_launch (GError **error)
1051 gchar *ret;
1052 gchar *machine_id;
1053 gchar *command_line;
1054 gchar *launch_stdout;
1055 gchar *launch_stderr;
1056 gint exit_status;
1057 gchar *old_dbus_verbose;
1058 gboolean restore_dbus_verbose;
1060 ret = NULL;
1061 machine_id = NULL;
1062 command_line = NULL;
1063 launch_stdout = NULL;
1064 launch_stderr = NULL;
1065 restore_dbus_verbose = FALSE;
1066 old_dbus_verbose = NULL;
1068 /* Don't run binaries as root if we're setuid. */
1069 if (GLIB_PRIVATE_CALL (g_check_setuid) ())
1071 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1072 _("Cannot spawn a message bus when setuid"));
1073 goto out;
1076 machine_id = _g_dbus_get_machine_id (error);
1077 if (machine_id == NULL)
1079 g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1080 goto out;
1083 if (g_getenv ("DISPLAY") == NULL)
1085 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1086 _("Cannot autolaunch D-Bus without X11 $DISPLAY"));
1087 goto out;
1090 /* We're using private libdbus facilities here. When everything
1091 * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1092 * X11 property is correctly documented right now) we should
1093 * consider using the spec instead of dbus-launch.
1095 * --autolaunch=MACHINEID
1096 * This option implies that dbus-launch should scan for a previ‐
1097 * ously-started session and reuse the values found there. If no
1098 * session is found, it will start a new session. The --exit-with-
1099 * session option is implied if --autolaunch is given. This option
1100 * is for the exclusive use of libdbus, you do not want to use it
1101 * manually. It may change in the future.
1104 /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1105 command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1107 if (G_UNLIKELY (_g_dbus_debug_address ()))
1109 _g_dbus_debug_print_lock ();
1110 g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
1111 old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1112 restore_dbus_verbose = TRUE;
1113 g_setenv ("DBUS_VERBOSE", "1", TRUE);
1114 _g_dbus_debug_print_unlock ();
1117 if (!g_spawn_command_line_sync (command_line,
1118 &launch_stdout,
1119 &launch_stderr,
1120 &exit_status,
1121 error))
1123 goto out;
1126 if (!g_spawn_check_exit_status (exit_status, error))
1128 g_prefix_error (error, _("Error spawning command line “%s”: "), command_line);
1129 goto out;
1132 /* From the dbus-launch(1) man page:
1134 * --binary-syntax Write to stdout a nul-terminated bus address,
1135 * then the bus PID as a binary integer of size sizeof(pid_t),
1136 * then the bus X window ID as a binary integer of size
1137 * sizeof(long). Integers are in the machine's byte order, not
1138 * network byte order or any other canonical byte order.
1140 ret = g_strdup (launch_stdout);
1142 out:
1143 if (G_UNLIKELY (_g_dbus_debug_address ()))
1145 gchar *s;
1146 _g_dbus_debug_print_lock ();
1147 g_print ("GDBus-debug:Address: dbus-launch output:");
1148 if (launch_stdout != NULL)
1150 s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1151 g_print ("\n%s", s);
1152 g_free (s);
1154 else
1156 g_print (" (none)\n");
1158 g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1159 if (launch_stderr != NULL)
1160 g_print ("\n%s", launch_stderr);
1161 else
1162 g_print (" (none)\n");
1163 _g_dbus_debug_print_unlock ();
1166 g_free (machine_id);
1167 g_free (command_line);
1168 g_free (launch_stdout);
1169 g_free (launch_stderr);
1170 if (G_UNLIKELY (restore_dbus_verbose))
1172 if (old_dbus_verbose != NULL)
1173 g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1174 else
1175 g_unsetenv ("DBUS_VERBOSE");
1177 g_free (old_dbus_verbose);
1178 return ret;
1181 /* end of G_OS_UNIX case */
1182 #elif defined(G_OS_WIN32)
1184 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1185 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1186 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1187 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1189 static void
1190 release_mutex (HANDLE mutex)
1192 ReleaseMutex (mutex);
1193 CloseHandle (mutex);
1196 static HANDLE
1197 acquire_mutex (const char *mutexname)
1199 HANDLE mutex;
1200 DWORD res;
1202 mutex = CreateMutexA (NULL, FALSE, mutexname);
1203 if (!mutex)
1204 return 0;
1206 res = WaitForSingleObject (mutex, INFINITE);
1207 switch (res)
1209 case WAIT_ABANDONED:
1210 release_mutex (mutex);
1211 return 0;
1212 case WAIT_FAILED:
1213 case WAIT_TIMEOUT:
1214 return 0;
1217 return mutex;
1220 static gboolean
1221 is_mutex_owned (const char *mutexname)
1223 HANDLE mutex;
1224 gboolean res = FALSE;
1226 mutex = CreateMutexA (NULL, FALSE, mutexname);
1227 if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1228 res = TRUE;
1229 else
1230 ReleaseMutex (mutex);
1231 CloseHandle (mutex);
1233 return res;
1236 static char *
1237 read_shm (const char *shm_name)
1239 HANDLE shared_mem;
1240 char *shared_data;
1241 char *res;
1242 int i;
1244 res = NULL;
1246 for (i = 0; i < 20; i++)
1248 shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1249 if (shared_mem != 0)
1250 break;
1251 Sleep (100);
1254 if (shared_mem != 0)
1256 shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1257 if (shared_data != NULL)
1259 res = g_strdup (shared_data);
1260 UnmapViewOfFile (shared_data);
1262 CloseHandle (shared_mem);
1265 return res;
1268 static HANDLE
1269 set_shm (const char *shm_name, const char *value)
1271 HANDLE shared_mem;
1272 char *shared_data;
1274 shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1275 0, strlen (value) + 1, shm_name);
1276 if (shared_mem == 0)
1277 return 0;
1279 shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1280 if (shared_data == NULL)
1281 return 0;
1283 strcpy (shared_data, value);
1285 UnmapViewOfFile (shared_data);
1287 return shared_mem;
1290 /* These keep state between publish_session_bus and unpublish_session_bus */
1291 static HANDLE published_daemon_mutex;
1292 static HANDLE published_shared_mem;
1294 static gboolean
1295 publish_session_bus (const char *address)
1297 HANDLE init_mutex;
1299 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1301 published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1302 if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1304 release_mutex (init_mutex);
1305 CloseHandle (published_daemon_mutex);
1306 published_daemon_mutex = NULL;
1307 return FALSE;
1310 published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1311 if (!published_shared_mem)
1313 release_mutex (init_mutex);
1314 CloseHandle (published_daemon_mutex);
1315 published_daemon_mutex = NULL;
1316 return FALSE;
1319 release_mutex (init_mutex);
1320 return TRUE;
1323 static void
1324 unpublish_session_bus (void)
1326 HANDLE init_mutex;
1328 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1330 CloseHandle (published_shared_mem);
1331 published_shared_mem = NULL;
1333 release_mutex (published_daemon_mutex);
1334 published_daemon_mutex = NULL;
1336 release_mutex (init_mutex);
1339 static void
1340 wait_console_window (void)
1342 FILE *console = fopen ("CONOUT$", "w");
1344 SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1345 fprintf (console, _("(Type any character to close this window)\n"));
1346 fflush (console);
1347 _getch ();
1350 static void
1351 open_console_window (void)
1353 if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1354 (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1356 if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1357 freopen ("CONOUT$", "w", stdout);
1359 if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1360 freopen ("CONOUT$", "w", stderr);
1362 SetConsoleTitleW (L"gdbus-daemon debug output.");
1364 atexit (wait_console_window);
1368 static void
1369 idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1371 GMainLoop *loop = user_data;
1372 g_main_loop_quit (loop);
1375 /* Satisfies STARTF_FORCEONFEEDBACK */
1376 static void
1377 turn_off_the_starting_cursor (void)
1379 MSG msg;
1380 BOOL bRet;
1382 PostQuitMessage (0);
1384 while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0)
1386 if (bRet == -1)
1387 continue;
1389 TranslateMessage (&msg);
1390 DispatchMessage (&msg);
1394 __declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
1396 __declspec(dllexport) void CALLBACK
1397 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1399 GDBusDaemon *daemon;
1400 GMainLoop *loop;
1401 const char *address;
1402 GError *error = NULL;
1404 turn_off_the_starting_cursor ();
1406 if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1407 open_console_window ();
1409 loop = g_main_loop_new (NULL, FALSE);
1411 address = "nonce-tcp:";
1412 daemon = _g_dbus_daemon_new (address, NULL, &error);
1413 if (daemon == NULL)
1415 g_printerr ("Can't init bus: %s\n", error->message);
1416 g_error_free (error);
1417 return;
1420 g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1422 if (publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1424 g_main_loop_run (loop);
1426 unpublish_session_bus ();
1429 g_main_loop_unref (loop);
1430 g_object_unref (daemon);
1433 static gchar *
1434 get_session_address_dbus_launch (GError **error)
1436 HANDLE autolaunch_mutex, init_mutex;
1437 char *address = NULL;
1438 wchar_t gio_path[MAX_PATH+1+200];
1440 autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1442 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1444 if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1445 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1447 release_mutex (init_mutex);
1449 if (address == NULL)
1451 gio_path[MAX_PATH] = 0;
1452 if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1454 PROCESS_INFORMATION pi = { 0 };
1455 STARTUPINFOW si = { 0 };
1456 BOOL res;
1457 wchar_t gio_path_short[MAX_PATH];
1458 wchar_t rundll_path[MAX_PATH*2];
1459 wchar_t args[MAX_PATH*4];
1461 GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1463 GetWindowsDirectoryW (rundll_path, MAX_PATH);
1464 wcscat (rundll_path, L"\\rundll32.exe");
1465 if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1467 GetSystemDirectoryW (rundll_path, MAX_PATH);
1468 wcscat (rundll_path, L"\\rundll32.exe");
1471 wcscpy (args, L"\"");
1472 wcscat (args, rundll_path);
1473 wcscat (args, L"\" ");
1474 wcscat (args, gio_path_short);
1475 #if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
1476 wcscat (args, L",g_win32_run_session_bus");
1477 #elif defined (_MSC_VER)
1478 wcscat (args, L",_g_win32_run_session_bus@16");
1479 #else
1480 wcscat (args, L",g_win32_run_session_bus@16");
1481 #endif
1483 res = CreateProcessW (rundll_path, args,
1484 0, 0, FALSE,
1485 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1486 0, NULL /* TODO: Should be root */,
1487 &si, &pi);
1488 if (res)
1489 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1493 release_mutex (autolaunch_mutex);
1495 if (address == NULL)
1496 g_set_error (error,
1497 G_IO_ERROR,
1498 G_IO_ERROR_FAILED,
1499 _("Session dbus not running, and autolaunch failed"));
1501 return address;
1503 #else /* neither G_OS_UNIX nor G_OS_WIN32 */
1504 static gchar *
1505 get_session_address_dbus_launch (GError **error)
1507 g_set_error (error,
1508 G_IO_ERROR,
1509 G_IO_ERROR_FAILED,
1510 _("Cannot determine session bus address (not implemented for this OS)"));
1511 return NULL;
1513 #endif /* neither G_OS_UNIX nor G_OS_WIN32 */
1515 /* ---------------------------------------------------------------------------------------------------- */
1517 static gchar *
1518 get_session_address_platform_specific (GError **error)
1520 gchar *ret;
1522 /* Use XDG_RUNTIME_DIR/bus if it exists and is suitable. This is appropriate
1523 * for systems using the "a session is a user-session" model described in
1524 * <http://lists.freedesktop.org/archives/dbus/2015-January/016522.html>,
1525 * and implemented in dbus >= 1.9.14 and sd-bus.
1527 * On systems following the more traditional "a session is a login-session"
1528 * model, this will fail and we'll fall through to X11 autolaunching
1529 * (dbus-launch) below.
1531 ret = get_session_address_xdg ();
1533 if (ret != NULL)
1534 return ret;
1536 /* TODO (#694472): try launchd on OS X, like
1537 * _dbus_lookup_session_address_launchd() does, since
1538 * 'dbus-launch --autolaunch' probably won't work there
1541 /* As a last resort, try the "autolaunch:" transport. On Unix this means
1542 * X11 autolaunching; on Windows this means a different autolaunching
1543 * mechanism based on shared memory.
1545 return get_session_address_dbus_launch (error);
1548 /* ---------------------------------------------------------------------------------------------------- */
1551 * g_dbus_address_get_for_bus_sync:
1552 * @bus_type: a #GBusType
1553 * @cancellable: (nullable): a #GCancellable or %NULL
1554 * @error: return location for error or %NULL
1556 * Synchronously looks up the D-Bus address for the well-known message
1557 * bus instance specified by @bus_type. This may involve using various
1558 * platform specific mechanisms.
1560 * The returned address will be in the
1561 * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
1563 * Returns: a valid D-Bus address string for @bus_type or %NULL if
1564 * @error is set
1566 * Since: 2.26
1568 gchar *
1569 g_dbus_address_get_for_bus_sync (GBusType bus_type,
1570 GCancellable *cancellable,
1571 GError **error)
1573 gchar *ret, *s = NULL;
1574 const gchar *starter_bus;
1575 GError *local_error;
1577 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1579 ret = NULL;
1580 local_error = NULL;
1582 if (G_UNLIKELY (_g_dbus_debug_address ()))
1584 guint n;
1585 _g_dbus_debug_print_lock ();
1586 s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1587 g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1589 g_free (s);
1590 for (n = 0; n < 3; n++)
1592 const gchar *k;
1593 const gchar *v;
1594 switch (n)
1596 case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1597 case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1598 case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1599 default: g_assert_not_reached ();
1601 v = g_getenv (k);
1602 g_print ("GDBus-debug:Address: env var %s", k);
1603 if (v != NULL)
1604 g_print ("='%s'\n", v);
1605 else
1606 g_print (" is not set\n");
1608 _g_dbus_debug_print_unlock ();
1611 switch (bus_type)
1613 case G_BUS_TYPE_SYSTEM:
1614 ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1615 if (ret == NULL)
1617 ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1619 break;
1621 case G_BUS_TYPE_SESSION:
1622 ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1623 if (ret == NULL)
1625 ret = get_session_address_platform_specific (&local_error);
1627 break;
1629 case G_BUS_TYPE_STARTER:
1630 starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1631 if (g_strcmp0 (starter_bus, "session") == 0)
1633 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1634 goto out;
1636 else if (g_strcmp0 (starter_bus, "system") == 0)
1638 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1639 goto out;
1641 else
1643 if (starter_bus != NULL)
1645 g_set_error (&local_error,
1646 G_IO_ERROR,
1647 G_IO_ERROR_FAILED,
1648 _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1649 " — unknown value “%s”"),
1650 starter_bus);
1652 else
1654 g_set_error_literal (&local_error,
1655 G_IO_ERROR,
1656 G_IO_ERROR_FAILED,
1657 _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1658 "variable is not set"));
1661 break;
1663 default:
1664 g_set_error (&local_error,
1665 G_IO_ERROR,
1666 G_IO_ERROR_FAILED,
1667 _("Unknown bus type %d"),
1668 bus_type);
1669 break;
1672 out:
1673 if (G_UNLIKELY (_g_dbus_debug_address ()))
1675 _g_dbus_debug_print_lock ();
1676 s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
1677 if (ret != NULL)
1679 g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1680 ret, s);
1682 else
1684 g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1685 s, local_error ? local_error->message : "");
1687 g_free (s);
1688 _g_dbus_debug_print_unlock ();
1691 if (local_error != NULL)
1692 g_propagate_error (error, local_error);
1694 return ret;
1698 * g_dbus_address_escape_value:
1699 * @string: an unescaped string to be included in a D-Bus address
1700 * as the value in a key-value pair
1702 * Escape @string so it can appear in a D-Bus address as the value
1703 * part of a key-value pair.
1705 * For instance, if @string is `/run/bus-for-:0`,
1706 * this function would return `/run/bus-for-%3A0`,
1707 * which could be used in a D-Bus address like
1708 * `unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0`.
1710 * Returns: (transfer full): a copy of @string with all
1711 * non-optionally-escaped bytes escaped
1713 * Since: 2.36
1715 gchar *
1716 g_dbus_address_escape_value (const gchar *string)
1718 GString *s;
1719 gsize i;
1721 g_return_val_if_fail (string != NULL, NULL);
1723 /* There will often not be anything needing escaping at all. */
1724 s = g_string_sized_new (strlen (string));
1726 /* D-Bus address escaping is mostly the same as URI escaping... */
1727 g_string_append_uri_escaped (s, string, "\\/", FALSE);
1729 /* ... but '~' is an unreserved character in URIs, but a
1730 * non-optionally-escaped character in D-Bus addresses. */
1731 for (i = 0; i < s->len; i++)
1733 if (G_UNLIKELY (s->str[i] == '~'))
1735 s->str[i] = '%';
1736 g_string_insert (s, i + 1, "7E");
1737 i += 2;
1741 return g_string_free (s, FALSE);