[kdbus] sync with kdbus (kdbus.h - commit: 5ae1ecac44cb)
[platform/upstream/glib.git] / gio / gdbusaddress.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27
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 "gsimpleasyncresult.h"
38 #include "glib-private.h"
39 #include "gdbusprivate.h"
40 #include "giomodule-priv.h"
41 #include "gdbusdaemon.h"
42
43 #ifdef G_OS_UNIX
44 #include <gio/gunixsocketaddress.h>
45 #include <gio/gkdbusconnection.h>
46 #endif
47
48 #ifdef G_OS_WIN32
49 #include <windows.h>
50 #include <io.h>
51 #include <conio.h>
52 #endif
53
54 #include "glibintl.h"
55
56 /**
57  * SECTION:gdbusaddress
58  * @title: D-Bus Addresses
59  * @short_description: D-Bus connection endpoints
60  * @include: gio/gio.h
61  *
62  * Routines for working with D-Bus addresses. A D-Bus address is a string
63  * like "unix:tmpdir=/tmp/my-app-name". The exact format of addresses
64  * is explained in detail in the [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html\#addresses).
65  */
66
67 static gchar *get_session_address_platform_specific (GError **error);
68
69 /* ---------------------------------------------------------------------------------------------------- */
70
71 /**
72  * g_dbus_is_address:
73  * @string: A string.
74  *
75  * Checks if @string is a D-Bus address.
76  *
77  * This doesn't check if @string is actually supported by #GDBusServer
78  * or #GDBusConnection - use g_dbus_is_supported_address() to do more
79  * checks.
80  *
81  * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
82  *
83  * Since: 2.26
84  */
85 gboolean
86 g_dbus_is_address (const gchar *string)
87 {
88   guint n;
89   gchar **a;
90   gboolean ret;
91
92   ret = FALSE;
93
94   g_return_val_if_fail (string != NULL, FALSE);
95
96   a = g_strsplit (string, ";", 0);
97   if (a[0] == NULL)
98     goto out;
99
100   for (n = 0; a[n] != NULL; n++)
101     {
102       if (!_g_dbus_address_parse_entry (a[n],
103                                         NULL,
104                                         NULL,
105                                         NULL))
106         goto out;
107     }
108
109   ret = TRUE;
110
111  out:
112   g_strfreev (a);
113   return ret;
114 }
115
116 static gboolean
117 is_valid_unix (const gchar  *address_entry,
118                GHashTable   *key_value_pairs,
119                GError      **error)
120 {
121   gboolean ret;
122   GList *keys;
123   GList *l;
124   const gchar *path;
125   const gchar *tmpdir;
126   const gchar *abstract;
127
128   ret = FALSE;
129   keys = NULL;
130   path = NULL;
131   tmpdir = NULL;
132   abstract = NULL;
133
134   keys = g_hash_table_get_keys (key_value_pairs);
135   for (l = keys; l != NULL; l = l->next)
136     {
137       const gchar *key = l->data;
138       if (g_strcmp0 (key, "path") == 0)
139         path = g_hash_table_lookup (key_value_pairs, key);
140       else if (g_strcmp0 (key, "tmpdir") == 0)
141         tmpdir = g_hash_table_lookup (key_value_pairs, key);
142       else if (g_strcmp0 (key, "abstract") == 0)
143         abstract = g_hash_table_lookup (key_value_pairs, key);
144       else
145         {
146           g_set_error (error,
147                        G_IO_ERROR,
148                        G_IO_ERROR_INVALID_ARGUMENT,
149                        _("Unsupported key '%s' in address entry '%s'"),
150                        key,
151                        address_entry);
152           goto out;
153         }
154     }
155
156   if (path != NULL)
157     {
158       if (tmpdir != NULL || abstract != NULL)
159         goto meaningless;
160     }
161   else if (tmpdir != NULL)
162     {
163       if (path != NULL || abstract != NULL)
164         goto meaningless;
165     }
166   else if (abstract != NULL)
167     {
168       if (path != NULL || tmpdir != NULL)
169         goto meaningless;
170     }
171   else
172     {
173       g_set_error (error,
174                    G_IO_ERROR,
175                    G_IO_ERROR_INVALID_ARGUMENT,
176                    _("Address '%s' is invalid (need exactly one of path, tmpdir or abstract keys)"),
177                    address_entry);
178       goto out;
179     }
180
181
182   ret= TRUE;
183   goto out;
184
185  meaningless:
186   g_set_error (error,
187                G_IO_ERROR,
188                G_IO_ERROR_INVALID_ARGUMENT,
189                _("Meaningless key/value pair combination in address entry '%s'"),
190                address_entry);
191
192  out:
193   g_list_free (keys);
194
195   return ret;
196 }
197
198 static gboolean
199 is_valid_nonce_tcp (const gchar  *address_entry,
200                     GHashTable   *key_value_pairs,
201                     GError      **error)
202 {
203   gboolean ret;
204   GList *keys;
205   GList *l;
206   const gchar *host;
207   const gchar *port;
208   const gchar *family;
209   const gchar *nonce_file;
210   gint port_num;
211   gchar *endp;
212
213   ret = FALSE;
214   keys = NULL;
215   host = NULL;
216   port = NULL;
217   family = NULL;
218   nonce_file = NULL;
219
220   keys = g_hash_table_get_keys (key_value_pairs);
221   for (l = keys; l != NULL; l = l->next)
222     {
223       const gchar *key = l->data;
224       if (g_strcmp0 (key, "host") == 0)
225         host = g_hash_table_lookup (key_value_pairs, key);
226       else if (g_strcmp0 (key, "port") == 0)
227         port = g_hash_table_lookup (key_value_pairs, key);
228       else if (g_strcmp0 (key, "family") == 0)
229         family = g_hash_table_lookup (key_value_pairs, key);
230       else if (g_strcmp0 (key, "noncefile") == 0)
231         nonce_file = g_hash_table_lookup (key_value_pairs, key);
232       else
233         {
234           g_set_error (error,
235                        G_IO_ERROR,
236                        G_IO_ERROR_INVALID_ARGUMENT,
237                        _("Unsupported key '%s' in address entry '%s'"),
238                        key,
239                        address_entry);
240           goto out;
241         }
242     }
243
244   if (port != NULL)
245     {
246       port_num = strtol (port, &endp, 10);
247       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
248         {
249           g_set_error (error,
250                        G_IO_ERROR,
251                        G_IO_ERROR_INVALID_ARGUMENT,
252                        _("Error in address '%s' - the port attribute is malformed"),
253                        address_entry);
254           goto out;
255         }
256     }
257
258   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
259     {
260       g_set_error (error,
261                    G_IO_ERROR,
262                    G_IO_ERROR_INVALID_ARGUMENT,
263                    _("Error in address '%s' - the family attribute is malformed"),
264                    address_entry);
265       goto out;
266     }
267
268   if (host != NULL)
269     {
270       /* TODO: validate host */
271     }
272
273   nonce_file = nonce_file; /* To avoid -Wunused-but-set-variable */
274
275   ret= TRUE;
276
277  out:
278   g_list_free (keys);
279
280   return ret;
281 }
282
283 static gboolean
284 is_valid_tcp (const gchar  *address_entry,
285               GHashTable   *key_value_pairs,
286               GError      **error)
287 {
288   gboolean ret;
289   GList *keys;
290   GList *l;
291   const gchar *host;
292   const gchar *port;
293   const gchar *family;
294   gint port_num;
295   gchar *endp;
296
297   ret = FALSE;
298   keys = NULL;
299   host = NULL;
300   port = NULL;
301   family = NULL;
302
303   keys = g_hash_table_get_keys (key_value_pairs);
304   for (l = keys; l != NULL; l = l->next)
305     {
306       const gchar *key = l->data;
307       if (g_strcmp0 (key, "host") == 0)
308         host = g_hash_table_lookup (key_value_pairs, key);
309       else if (g_strcmp0 (key, "port") == 0)
310         port = g_hash_table_lookup (key_value_pairs, key);
311       else if (g_strcmp0 (key, "family") == 0)
312         family = g_hash_table_lookup (key_value_pairs, key);
313       else
314         {
315           g_set_error (error,
316                        G_IO_ERROR,
317                        G_IO_ERROR_INVALID_ARGUMENT,
318                        _("Unsupported key '%s' in address entry '%s'"),
319                        key,
320                        address_entry);
321           goto out;
322         }
323     }
324
325   if (port != NULL)
326     {
327       port_num = strtol (port, &endp, 10);
328       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
329         {
330           g_set_error (error,
331                        G_IO_ERROR,
332                        G_IO_ERROR_INVALID_ARGUMENT,
333                        _("Error in address '%s' - the port attribute is malformed"),
334                        address_entry);
335           goto out;
336         }
337     }
338
339   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
340     {
341       g_set_error (error,
342                    G_IO_ERROR,
343                    G_IO_ERROR_INVALID_ARGUMENT,
344                    _("Error in address '%s' - the family attribute is malformed"),
345                    address_entry);
346       goto out;
347     }
348
349   if (host != NULL)
350     {
351       /* TODO: validate host */
352     }
353
354   ret= TRUE;
355
356  out:
357   g_list_free (keys);
358
359   return ret;
360 }
361
362 static int
363 g_dbus_is_supported_address_kdbus (const gchar  *transport_name)
364 {
365   int supported = 0;
366
367   supported = g_strcmp0 (transport_name, "kernel") == 0;
368
369   return supported;
370 }
371
372 /**
373  * g_dbus_is_supported_address:
374  * @string: A string.
375  * @error: Return location for error or %NULL.
376  *
377  * Like g_dbus_is_address() but also checks if the library suppors the
378  * transports in @string and that key/value pairs for each transport
379  * are valid.
380  *
381  * Returns: %TRUE if @string is a valid D-Bus address that is
382  * supported by this library, %FALSE if @error is set.
383  *
384  * Since: 2.26
385  */
386 gboolean
387 g_dbus_is_supported_address (const gchar  *string,
388                              GError      **error)
389 {
390   guint n;
391   gchar **a;
392   gboolean ret;
393
394   ret = FALSE;
395
396   g_return_val_if_fail (string != NULL, FALSE);
397   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
398
399   a = g_strsplit (string, ";", 0);
400   for (n = 0; a[n] != NULL; n++)
401     {
402       gchar *transport_name;
403       GHashTable *key_value_pairs;
404       gboolean supported;
405
406       if (!_g_dbus_address_parse_entry (a[n],
407                                         &transport_name,
408                                         &key_value_pairs,
409                                         error))
410         goto out;
411
412       supported = FALSE;
413       if ((g_strcmp0 (transport_name, "unix") == 0)
414           || g_dbus_is_supported_address_kdbus (transport_name))
415         supported = is_valid_unix (a[n], key_value_pairs, error);
416       else if (g_strcmp0 (transport_name, "tcp") == 0)
417         supported = is_valid_tcp (a[n], key_value_pairs, error);
418       else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
419         supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
420       else if (g_strcmp0 (a[n], "autolaunch:") == 0)
421         supported = TRUE;
422
423       g_free (transport_name);
424       g_hash_table_unref (key_value_pairs);
425
426       if (!supported)
427         goto out;
428     }
429
430   ret = TRUE;
431
432  out:
433   g_strfreev (a);
434
435   g_assert (ret || (!ret && (error == NULL || *error != NULL)));
436
437   return ret;
438 }
439
440 gboolean
441 _g_dbus_address_parse_entry (const gchar  *address_entry,
442                              gchar       **out_transport_name,
443                              GHashTable  **out_key_value_pairs,
444                              GError      **error)
445 {
446   gboolean ret;
447   GHashTable *key_value_pairs;
448   gchar *transport_name;
449   gchar **kv_pairs;
450   const gchar *s;
451   guint n;
452
453   ret = FALSE;
454   kv_pairs = NULL;
455   transport_name = NULL;
456   key_value_pairs = NULL;
457
458   s = strchr (address_entry, ':');
459   if (s == NULL)
460     {
461       g_set_error (error,
462                    G_IO_ERROR,
463                    G_IO_ERROR_INVALID_ARGUMENT,
464                    _("Address element '%s' does not contain a colon (:)"),
465                    address_entry);
466       goto out;
467     }
468
469   transport_name = g_strndup (address_entry, s - address_entry);
470   key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
471
472   kv_pairs = g_strsplit (s + 1, ",", 0);
473   for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
474     {
475       const gchar *kv_pair = kv_pairs[n];
476       gchar *key;
477       gchar *value;
478
479       s = strchr (kv_pair, '=');
480       if (s == NULL)
481         {
482           g_set_error (error,
483                        G_IO_ERROR,
484                        G_IO_ERROR_INVALID_ARGUMENT,
485                        _("Key/Value pair %d, '%s', in address element '%s' does not contain an equal sign"),
486                        n,
487                        kv_pair,
488                        address_entry);
489           goto out;
490         }
491
492       key = g_uri_unescape_segment (kv_pair, s, NULL);
493       value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
494       if (key == NULL || value == NULL)
495         {
496           g_set_error (error,
497                        G_IO_ERROR,
498                        G_IO_ERROR_INVALID_ARGUMENT,
499                        _("Error unescaping key or value in Key/Value pair %d, '%s', in address element '%s'"),
500                        n,
501                        kv_pair,
502                        address_entry);
503           g_free (key);
504           g_free (value);
505           goto out;
506         }
507       g_hash_table_insert (key_value_pairs, key, value);
508     }
509
510   ret = TRUE;
511
512 out:
513   g_strfreev (kv_pairs);
514   if (ret)
515     {
516       if (out_transport_name != NULL)
517         *out_transport_name = transport_name;
518       else
519         g_free (transport_name);
520       if (out_key_value_pairs != NULL)
521         *out_key_value_pairs = key_value_pairs;
522       else if (key_value_pairs != NULL)
523         g_hash_table_unref (key_value_pairs);
524     }
525   else
526     {
527       g_free (transport_name);
528       if (key_value_pairs != NULL)
529         g_hash_table_unref (key_value_pairs);
530     }
531   return ret;
532 }
533
534 /* ---------------------------------------------------------------------------------------------------- */
535
536 static GIOStream *
537 g_dbus_address_try_connect_one (const gchar   *address_entry,
538                                 gchar        **out_guid,
539                                 GCancellable  *cancellable,
540                                 GError       **error);
541
542 /* TODO: Declare an extension point called GDBusTransport (or similar)
543  * and move code below to extensions implementing said extension
544  * point. That way we can implement a D-Bus transport over X11 without
545  * making libgio link to libX11...
546  */
547 static GIOStream *
548 g_dbus_address_connect (const gchar   *address_entry,
549                         const gchar   *transport_name,
550                         GHashTable    *key_value_pairs,
551                         GCancellable  *cancellable,
552                         GError       **error)
553 {
554   GIOStream *ret;
555   GSocketConnectable *connectable;
556   const gchar *nonce_file;
557
558   connectable = NULL;
559   ret = NULL;
560   nonce_file = NULL;
561
562   if (FALSE)
563     {
564     }
565 #ifdef G_OS_UNIX
566   if ((g_strcmp0 (transport_name, "unix") == 0)
567       || g_dbus_is_supported_address_kdbus (transport_name))
568     {
569       const gchar *path;
570       const gchar *abstract;
571       path = g_hash_table_lookup (key_value_pairs, "path");
572       abstract = g_hash_table_lookup (key_value_pairs, "abstract");
573       if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
574         {
575           g_set_error (error,
576                        G_IO_ERROR,
577                        G_IO_ERROR_INVALID_ARGUMENT,
578                        _("Error in address '%s' - the unix transport requires exactly one of the "
579                          "keys 'path' or 'abstract' to be set"),
580                        address_entry);
581         }
582       else if (path != NULL)
583         {
584           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
585         }
586       else if (abstract != NULL)
587         {
588           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
589                                                                                    -1,
590                                                                                    G_UNIX_SOCKET_ADDRESS_ABSTRACT));
591         }
592       else
593         {
594           g_assert_not_reached ();
595         }
596     }
597 #endif
598   else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
599     {
600       const gchar *s;
601       const gchar *host;
602       glong port;
603       gchar *endp;
604       gboolean is_nonce;
605
606       is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
607
608       host = g_hash_table_lookup (key_value_pairs, "host");
609       if (host == NULL)
610         {
611           g_set_error (error,
612                        G_IO_ERROR,
613                        G_IO_ERROR_INVALID_ARGUMENT,
614                        _("Error in address '%s' - the host attribute is missing or malformed"),
615                        address_entry);
616           goto out;
617         }
618
619       s = g_hash_table_lookup (key_value_pairs, "port");
620       if (s == NULL)
621         s = "0";
622       port = strtol (s, &endp, 10);
623       if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
624         {
625           g_set_error (error,
626                        G_IO_ERROR,
627                        G_IO_ERROR_INVALID_ARGUMENT,
628                        _("Error in address '%s' - the port attribute is missing or malformed"),
629                        address_entry);
630           goto out;
631         }
632
633
634       if (is_nonce)
635         {
636           nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
637           if (nonce_file == NULL)
638             {
639               g_set_error (error,
640                            G_IO_ERROR,
641                            G_IO_ERROR_INVALID_ARGUMENT,
642                            _("Error in address '%s' - the noncefile attribute is missing or malformed"),
643                            address_entry);
644               goto out;
645             }
646         }
647
648       /* TODO: deal with family key/value-pair */
649       connectable = g_network_address_new (host, port);
650     }
651   else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
652     {
653       gchar *autolaunch_address;
654       autolaunch_address = get_session_address_platform_specific (error);
655       if (autolaunch_address != NULL)
656         {
657           ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
658           g_free (autolaunch_address);
659           goto out;
660         }
661       else
662         {
663           g_prefix_error (error, _("Error auto-launching: "));
664         }
665     }
666   else
667     {
668       g_set_error (error,
669                    G_IO_ERROR,
670                    G_IO_ERROR_INVALID_ARGUMENT,
671                    _("Unknown or unsupported transport '%s' for address '%s'"),
672                    transport_name,
673                    address_entry);
674     }
675
676   if (connectable != NULL)
677     {
678
679       if (g_dbus_is_supported_address_kdbus (transport_name))
680         {
681           GKdbusConnection *connection;
682           gboolean status;
683
684           const gchar *path;
685           path = g_hash_table_lookup (key_value_pairs, "path");
686
687           g_assert (ret == NULL);
688           connection = _g_kdbus_connection_new ();
689           status = _g_kdbus_connection_connect (connection,
690                                                 path,
691                                                 cancellable,
692                                                 error);
693           g_object_unref (connectable);
694
695           if (!status)
696             goto out;
697
698           ret = G_IO_STREAM (connection);
699         }
700       else
701         {
702           GSocketClient *client;
703           GSocketConnection *connection;
704
705           g_assert (ret == NULL);
706           client = g_socket_client_new ();
707           connection = g_socket_client_connect (client,
708                                                 connectable,
709                                                 cancellable,
710                                                 error);
711           g_object_unref (connectable);
712           g_object_unref (client);
713           if (connection == NULL)
714             goto out;
715
716           ret = G_IO_STREAM (connection);
717         }
718
719       if (nonce_file != NULL)
720         {
721           gchar nonce_contents[16 + 1];
722           size_t num_bytes_read;
723           FILE *f;
724
725           /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
726           f = fopen (nonce_file, "rb");
727           if (f == NULL)
728             {
729               g_set_error (error,
730                            G_IO_ERROR,
731                            G_IO_ERROR_INVALID_ARGUMENT,
732                            _("Error opening nonce file '%s': %s"),
733                            nonce_file,
734                            g_strerror (errno));
735               g_object_unref (ret);
736               ret = NULL;
737               goto out;
738             }
739           num_bytes_read = fread (nonce_contents,
740                                   sizeof (gchar),
741                                   16 + 1,
742                                   f);
743           if (num_bytes_read != 16)
744             {
745               if (num_bytes_read == 0)
746                 {
747                   g_set_error (error,
748                                G_IO_ERROR,
749                                G_IO_ERROR_INVALID_ARGUMENT,
750                                _("Error reading from nonce file '%s': %s"),
751                                nonce_file,
752                                g_strerror (errno));
753                 }
754               else
755                 {
756                   g_set_error (error,
757                                G_IO_ERROR,
758                                G_IO_ERROR_INVALID_ARGUMENT,
759                                _("Error reading from nonce file '%s', expected 16 bytes, got %d"),
760                                nonce_file,
761                                (gint) num_bytes_read);
762                 }
763               g_object_unref (ret);
764               ret = NULL;
765               fclose (f);
766               goto out;
767             }
768           fclose (f);
769
770           if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
771                                           nonce_contents,
772                                           16,
773                                           NULL,
774                                           cancellable,
775                                           error))
776             {
777               g_prefix_error (error, _("Error writing contents of nonce file '%s' to stream:"), nonce_file);
778               g_object_unref (ret);
779               ret = NULL;
780               goto out;
781             }
782         }
783     }
784
785  out:
786
787   return ret;
788 }
789
790 static GIOStream *
791 g_dbus_address_try_connect_one (const gchar   *address_entry,
792                                 gchar        **out_guid,
793                                 GCancellable  *cancellable,
794                                 GError       **error)
795 {
796   GIOStream *ret;
797   GHashTable *key_value_pairs;
798   gchar *transport_name;
799   const gchar *guid;
800
801   ret = NULL;
802   transport_name = NULL;
803   key_value_pairs = NULL;
804
805   if (!_g_dbus_address_parse_entry (address_entry,
806                                     &transport_name,
807                                     &key_value_pairs,
808                                     error))
809     goto out;
810
811   ret = g_dbus_address_connect (address_entry,
812                                 transport_name,
813                                 key_value_pairs,
814                                 cancellable,
815                                 error);
816   if (ret == NULL)
817     goto out;
818
819   guid = g_hash_table_lookup (key_value_pairs, "guid");
820   if (guid != NULL && out_guid != NULL)
821     *out_guid = g_strdup (guid);
822
823 out:
824   g_free (transport_name);
825   if (key_value_pairs != NULL)
826     g_hash_table_unref (key_value_pairs);
827   return ret;
828 }
829
830
831 /* ---------------------------------------------------------------------------------------------------- */
832
833 typedef struct {
834   gchar *address;
835   GIOStream *stream;
836   gchar *guid;
837 } GetStreamData;
838
839 static void
840 get_stream_data_free (GetStreamData *data)
841 {
842   g_free (data->address);
843   if (data->stream != NULL)
844     g_object_unref (data->stream);
845   g_free (data->guid);
846   g_free (data);
847 }
848
849 static void
850 get_stream_thread_func (GSimpleAsyncResult *res,
851                         GObject            *object,
852                         GCancellable       *cancellable)
853 {
854   GetStreamData *data;
855   GError *error;
856
857   data = g_simple_async_result_get_op_res_gpointer (res);
858
859   error = NULL;
860   data->stream = g_dbus_address_get_stream_sync (data->address,
861                                                  &data->guid,
862                                                  cancellable,
863                                                  &error);
864   if (data->stream == NULL)
865     g_simple_async_result_take_error (res, error);
866 }
867
868 /**
869  * g_dbus_address_get_stream:
870  * @address: A valid D-Bus address.
871  * @cancellable: (allow-none): A #GCancellable or %NULL.
872  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
873  * @user_data: Data to pass to @callback.
874  *
875  * Asynchronously connects to an endpoint specified by @address and
876  * sets up the connection so it is in a state to run the client-side
877  * of the D-Bus authentication conversation.
878  *
879  * When the operation is finished, @callback will be invoked. You can
880  * then call g_dbus_address_get_stream_finish() to get the result of
881  * the operation.
882  *
883  * This is an asynchronous failable function. See
884  * g_dbus_address_get_stream_sync() for the synchronous version.
885  *
886  * Since: 2.26
887  */
888 void
889 g_dbus_address_get_stream (const gchar         *address,
890                            GCancellable        *cancellable,
891                            GAsyncReadyCallback  callback,
892                            gpointer             user_data)
893 {
894   GSimpleAsyncResult *res;
895   GetStreamData *data;
896
897   g_return_if_fail (address != NULL);
898
899   res = g_simple_async_result_new (NULL,
900                                    callback,
901                                    user_data,
902                                    g_dbus_address_get_stream);
903   g_simple_async_result_set_check_cancellable (res, cancellable);
904   data = g_new0 (GetStreamData, 1);
905   data->address = g_strdup (address);
906   g_simple_async_result_set_op_res_gpointer (res,
907                                              data,
908                                              (GDestroyNotify) get_stream_data_free);
909   g_simple_async_result_run_in_thread (res,
910                                        get_stream_thread_func,
911                                        G_PRIORITY_DEFAULT,
912                                        cancellable);
913   g_object_unref (res);
914 }
915
916 /**
917  * g_dbus_address_get_stream_finish:
918  * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
919  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
920  * @error: Return location for error or %NULL.
921  *
922  * Finishes an operation started with g_dbus_address_get_stream().
923  *
924  * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
925  *
926  * Since: 2.26
927  */
928 GIOStream *
929 g_dbus_address_get_stream_finish (GAsyncResult        *res,
930                                   gchar              **out_guid,
931                                   GError             **error)
932 {
933   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
934   GetStreamData *data;
935   GIOStream *ret;
936
937   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
938   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
939
940   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
941
942   ret = NULL;
943
944   data = g_simple_async_result_get_op_res_gpointer (simple);
945   if (g_simple_async_result_propagate_error (simple, error))
946     goto out;
947
948   ret = g_object_ref (data->stream);
949   if (out_guid != NULL)
950     *out_guid = g_strdup (data->guid);
951
952  out:
953   return ret;
954 }
955
956 /**
957  * g_dbus_address_get_stream_sync:
958  * @address: A valid D-Bus address.
959  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
960  * @cancellable: (allow-none): A #GCancellable or %NULL.
961  * @error: Return location for error or %NULL.
962  *
963  * Synchronously connects to an endpoint specified by @address and
964  * sets up the connection so it is in a state to run the client-side
965  * of the D-Bus authentication conversation.
966  *
967  * This is a synchronous failable function. See
968  * g_dbus_address_get_stream() for the asynchronous version.
969  *
970  * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
971  *
972  * Since: 2.26
973  */
974 GIOStream *
975 g_dbus_address_get_stream_sync (const gchar   *address,
976                                 gchar        **out_guid,
977                                 GCancellable  *cancellable,
978                                 GError       **error)
979 {
980   GIOStream *ret;
981   gchar **addr_array;
982   guint n;
983   GError *last_error;
984
985   g_return_val_if_fail (address != NULL, NULL);
986   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
987
988   ret = NULL;
989   last_error = NULL;
990
991   addr_array = g_strsplit (address, ";", 0);
992   if (addr_array != NULL && addr_array[0] == NULL)
993     {
994       last_error = g_error_new_literal (G_IO_ERROR,
995                                         G_IO_ERROR_INVALID_ARGUMENT,
996                                         _("The given address is empty"));
997       goto out;
998     }
999
1000   for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
1001     {
1002       const gchar *addr = addr_array[n];
1003       GError *this_error;
1004
1005       this_error = NULL;
1006       ret = g_dbus_address_try_connect_one (addr,
1007                                             out_guid,
1008                                             cancellable,
1009                                             &this_error);
1010       if (ret != NULL)
1011         {
1012           goto out;
1013         }
1014       else
1015         {
1016           g_assert (this_error != NULL);
1017           if (last_error != NULL)
1018             g_error_free (last_error);
1019           last_error = this_error;
1020         }
1021     }
1022
1023  out:
1024   if (ret != NULL)
1025     {
1026       if (last_error != NULL)
1027         g_error_free (last_error);
1028     }
1029   else
1030     {
1031       g_assert (last_error != NULL);
1032       g_propagate_error (error, last_error);
1033     }
1034
1035   g_strfreev (addr_array);
1036   return ret;
1037 }
1038
1039 /* ---------------------------------------------------------------------------------------------------- */
1040
1041 #ifdef G_OS_UNIX
1042 static gchar *
1043 get_session_address_dbus_launch (GError **error)
1044 {
1045   gchar *ret;
1046   gchar *machine_id;
1047   gchar *command_line;
1048   gchar *launch_stdout;
1049   gchar *launch_stderr;
1050   gint exit_status;
1051   gchar *old_dbus_verbose;
1052   gboolean restore_dbus_verbose;
1053
1054   ret = NULL;
1055   machine_id = NULL;
1056   command_line = NULL;
1057   launch_stdout = NULL;
1058   launch_stderr = NULL;
1059   restore_dbus_verbose = FALSE;
1060   old_dbus_verbose = NULL;
1061
1062   /* Don't run binaries as root if we're setuid. */
1063   if (GLIB_PRIVATE_CALL (g_check_setuid) ())
1064     {
1065       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1066                    _("Cannot spawn a message bus when setuid"));
1067       goto out;
1068     }
1069
1070   machine_id = _g_dbus_get_machine_id (error);
1071   if (machine_id == NULL)
1072     {
1073       g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1074       goto out;
1075     }
1076
1077   /* We're using private libdbus facilities here. When everything
1078    * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1079    * X11 property is correctly documented right now) we should
1080    * consider using the spec instead of dbus-launch.
1081    *
1082    *   --autolaunch=MACHINEID
1083    *          This option implies that dbus-launch should scan  for  a  previ‐
1084    *          ously-started  session  and  reuse the values found there. If no
1085    *          session is found, it will start a new session. The  --exit-with-
1086    *          session option is implied if --autolaunch is given.  This option
1087    *          is for the exclusive use of libdbus, you do not want to  use  it
1088    *          manually. It may change in the future.
1089    */
1090
1091   /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1092   command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1093
1094   if (G_UNLIKELY (_g_dbus_debug_address ()))
1095     {
1096       _g_dbus_debug_print_lock ();
1097       g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
1098       old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1099       restore_dbus_verbose = TRUE;
1100       g_setenv ("DBUS_VERBOSE", "1", TRUE);
1101       _g_dbus_debug_print_unlock ();
1102     }
1103
1104   if (!g_spawn_command_line_sync (command_line,
1105                                   &launch_stdout,
1106                                   &launch_stderr,
1107                                   &exit_status,
1108                                   error))
1109     {
1110       goto out;
1111     }
1112
1113   if (!g_spawn_check_exit_status (exit_status, error))
1114     {
1115       g_prefix_error (error, _("Error spawning command line '%s': "), command_line);
1116       goto out;
1117     }
1118
1119   /* From the dbus-launch(1) man page:
1120    *
1121    *   --binary-syntax Write to stdout a nul-terminated bus address,
1122    *   then the bus PID as a binary integer of size sizeof(pid_t),
1123    *   then the bus X window ID as a binary integer of size
1124    *   sizeof(long).  Integers are in the machine's byte order, not
1125    *   network byte order or any other canonical byte order.
1126    */
1127   ret = g_strdup (launch_stdout);
1128
1129  out:
1130   if (G_UNLIKELY (_g_dbus_debug_address ()))
1131     {
1132       gchar *s;
1133       _g_dbus_debug_print_lock ();
1134       g_print ("GDBus-debug:Address: dbus-launch output:");
1135       if (launch_stdout != NULL)
1136         {
1137           s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1138           g_print ("\n%s", s);
1139           g_free (s);
1140         }
1141       else
1142         {
1143           g_print (" (none)\n");
1144         }
1145       g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1146       if (launch_stderr != NULL)
1147         g_print ("\n%s", launch_stderr);
1148       else
1149         g_print (" (none)\n");
1150       _g_dbus_debug_print_unlock ();
1151     }
1152
1153   g_free (machine_id);
1154   g_free (command_line);
1155   g_free (launch_stdout);
1156   g_free (launch_stderr);
1157   if (G_UNLIKELY (restore_dbus_verbose))
1158     {
1159       if (old_dbus_verbose != NULL)
1160         g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1161       else
1162         g_unsetenv ("DBUS_VERBOSE");
1163     }
1164   g_free (old_dbus_verbose);
1165   return ret;
1166 }
1167 #endif
1168
1169 #ifdef G_OS_WIN32
1170
1171 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1172 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1173 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1174 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1175
1176 static void
1177 release_mutex (HANDLE mutex)
1178 {
1179   ReleaseMutex (mutex);
1180   CloseHandle (mutex);
1181 }
1182
1183 static HANDLE
1184 acquire_mutex (const char *mutexname)
1185 {
1186   HANDLE mutex;
1187   DWORD res;
1188
1189   mutex = CreateMutexA (NULL, FALSE, mutexname);
1190   if (!mutex)
1191     return 0;
1192
1193   res = WaitForSingleObject (mutex, INFINITE);
1194   switch (res)
1195     {
1196     case WAIT_ABANDONED:
1197       release_mutex (mutex);
1198       return 0;
1199     case WAIT_FAILED:
1200     case WAIT_TIMEOUT:
1201       return 0;
1202     }
1203
1204   return mutex;
1205 }
1206
1207 static gboolean
1208 is_mutex_owned (const char *mutexname)
1209 {
1210   HANDLE mutex;
1211   gboolean res = FALSE;
1212
1213   mutex = CreateMutexA (NULL, FALSE, mutexname);
1214   if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1215     res = TRUE;
1216   else
1217     ReleaseMutex (mutex);
1218   CloseHandle (mutex);
1219
1220   return res;
1221 }
1222
1223 static char *
1224 read_shm (const char *shm_name)
1225 {
1226   HANDLE shared_mem;
1227   char *shared_data;
1228   char *res;
1229   int i;
1230
1231   res = NULL;
1232
1233   for (i = 0; i < 20; i++)
1234     {
1235       shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1236       if (shared_mem != 0)
1237         break;
1238       Sleep (100);
1239     }
1240
1241   if (shared_mem != 0)
1242     {
1243       shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1244       if (shared_data != NULL)
1245         {
1246           res = g_strdup (shared_data);
1247           UnmapViewOfFile (shared_data);
1248         }
1249       CloseHandle (shared_mem);
1250     }
1251
1252   return res;
1253 }
1254
1255 static HANDLE
1256 set_shm (const char *shm_name, const char *value)
1257 {
1258   HANDLE shared_mem;
1259   char *shared_data;
1260
1261   shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1262                                    0, strlen (value) + 1, shm_name);
1263   if (shared_mem == 0)
1264     return 0;
1265
1266   shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1267   if (shared_data == NULL)
1268     return 0;
1269
1270   strcpy (shared_data, value);
1271
1272   UnmapViewOfFile (shared_data);
1273
1274   return shared_mem;
1275 }
1276
1277 /* These keep state between publish_session_bus and unpublish_session_bus */
1278 static HANDLE published_daemon_mutex;
1279 static HANDLE published_shared_mem;
1280
1281 static gboolean
1282 publish_session_bus (const char *address)
1283 {
1284   HANDLE init_mutex;
1285
1286   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1287
1288   published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1289   if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1290     {
1291       release_mutex (init_mutex);
1292       CloseHandle (published_daemon_mutex);
1293       published_daemon_mutex = NULL;
1294       return FALSE;
1295     }
1296
1297   published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1298   if (!published_shared_mem)
1299     {
1300       release_mutex (init_mutex);
1301       CloseHandle (published_daemon_mutex);
1302       published_daemon_mutex = NULL;
1303       return FALSE;
1304     }
1305
1306   release_mutex (init_mutex);
1307   return TRUE;
1308 }
1309
1310 static void
1311 unpublish_session_bus (void)
1312 {
1313   HANDLE init_mutex;
1314
1315   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1316
1317   CloseHandle (published_shared_mem);
1318   published_shared_mem = NULL;
1319
1320   release_mutex (published_daemon_mutex);
1321   published_daemon_mutex = NULL;
1322
1323   release_mutex (init_mutex);
1324 }
1325
1326 static void
1327 wait_console_window (void)
1328 {
1329   FILE *console = fopen ("CONOUT$", "w");
1330
1331   SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1332   fprintf (console, _("(Type any character to close this window)\n"));
1333   fflush (console);
1334   _getch ();
1335 }
1336
1337 static void
1338 open_console_window (void)
1339 {
1340   if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1341        (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1342     {
1343       if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1344         freopen ("CONOUT$", "w", stdout);
1345
1346       if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1347         freopen ("CONOUT$", "w", stderr);
1348
1349       SetConsoleTitleW (L"gdbus-daemon debug output.");
1350
1351       atexit (wait_console_window);
1352     }
1353 }
1354 static void
1355 idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1356 {
1357   GMainLoop *loop = user_data;
1358   g_main_loop_quit (loop);
1359 }
1360
1361 __declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
1362
1363 __declspec(dllexport) void CALLBACK
1364 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1365 {
1366   GDBusDaemon *daemon;
1367   GMainLoop *loop;
1368   const char *address;
1369   GError *error = NULL;
1370
1371   if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1372     open_console_window ();
1373
1374   loop = g_main_loop_new (NULL, FALSE);
1375
1376   address = "nonce-tcp:";
1377   daemon = _g_dbus_daemon_new (address, NULL, &error);
1378   if (daemon == NULL)
1379     {
1380       g_printerr ("Can't init bus: %s\n", error->message);
1381       return;
1382     }
1383
1384   g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1385
1386   if ( publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1387     {
1388       g_main_loop_run (loop);
1389
1390       unpublish_session_bus ();
1391     }
1392
1393   g_main_loop_unref (loop);
1394   g_object_unref (daemon);
1395 }
1396
1397 static gchar *
1398 get_session_address_dbus_launch (GError **error)
1399 {
1400   HANDLE autolaunch_mutex, init_mutex;
1401   char *address = NULL;
1402   wchar_t gio_path[MAX_PATH+1+200];
1403
1404   autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1405
1406   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1407
1408   if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1409     address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1410
1411   release_mutex (init_mutex);
1412
1413   if (address == NULL)
1414     {
1415       gio_path[MAX_PATH] = 0;
1416       if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1417         {
1418           PROCESS_INFORMATION pi = { 0 };
1419           STARTUPINFOW si = { 0 };
1420           BOOL res;
1421           wchar_t gio_path_short[MAX_PATH];
1422           wchar_t rundll_path[MAX_PATH*2];
1423           wchar_t args[MAX_PATH*4];
1424
1425           GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1426
1427           GetWindowsDirectoryW (rundll_path, MAX_PATH);
1428           wcscat (rundll_path, L"\\rundll32.exe");
1429           if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1430             {
1431               GetSystemDirectoryW (rundll_path, MAX_PATH);
1432               wcscat (rundll_path, L"\\rundll32.exe");
1433             }
1434
1435           wcscpy (args, L"\"");
1436           wcscat (args, rundll_path);
1437           wcscat (args, L"\" ");
1438           wcscat (args, gio_path_short);
1439 #if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
1440           wcscat (args, L",g_win32_run_session_bus");
1441 #elif defined (_MSC_VER)
1442           wcscat (args, L",_g_win32_run_session_bus@16");
1443 #else
1444           wcscat (args, L",g_win32_run_session_bus@16");
1445 #endif
1446
1447           res = CreateProcessW (rundll_path, args,
1448                                 0, 0, FALSE,
1449                                 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1450                                 0, NULL /* TODO: Should be root */,
1451                                 &si, &pi);
1452           if (res)
1453             address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1454         }
1455     }
1456
1457   release_mutex (autolaunch_mutex);
1458
1459   if (address == NULL)
1460     g_set_error (error,
1461                  G_IO_ERROR,
1462                  G_IO_ERROR_FAILED,
1463                  _("Session dbus not running, and autolaunch failed"));
1464
1465   return address;
1466 }
1467 #endif
1468
1469 /* ---------------------------------------------------------------------------------------------------- */
1470
1471 static gchar *
1472 get_session_address_platform_specific (GError **error)
1473 {
1474   gchar *ret;
1475 #if defined (G_OS_UNIX) || defined(G_OS_WIN32)
1476   /* need to handle OS X in a different way since 'dbus-launch --autolaunch' probably won't work there */
1477   ret = get_session_address_dbus_launch (error);
1478 #else
1479   /* TODO: implement for OS X */
1480   ret = NULL;
1481   g_set_error (error,
1482                G_IO_ERROR,
1483                G_IO_ERROR_FAILED,
1484                _("Cannot determine session bus address (not implemented for this OS)"));
1485 #endif
1486   return ret;
1487 }
1488
1489 /* ---------------------------------------------------------------------------------------------------- */
1490
1491 /**
1492  * g_dbus_address_get_for_bus_sync:
1493  * @bus_type: a #GBusType
1494  * @cancellable: (allow-none): a #GCancellable or %NULL
1495  * @error: return location for error or %NULL
1496  *
1497  * Synchronously looks up the D-Bus address for the well-known message
1498  * bus instance specified by @bus_type. This may involve using various
1499  * platform specific mechanisms.
1500  *
1501  * Returns: a valid D-Bus address string for @bus_type or %NULL if
1502  *     @error is set
1503  *
1504  * Since: 2.26
1505  */
1506 gchar *
1507 g_dbus_address_get_for_bus_sync (GBusType       bus_type,
1508                                  GCancellable  *cancellable,
1509                                  GError       **error)
1510 {
1511   gchar *ret;
1512   const gchar *system_bus;
1513   const gchar *session_bus;
1514   const gchar *starter_bus;
1515   GError *local_error;
1516
1517   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1518
1519   ret = NULL;
1520   local_error = NULL;
1521
1522   if (G_UNLIKELY (_g_dbus_debug_address ()))
1523     {
1524       guint n;
1525       _g_dbus_debug_print_lock ();
1526       g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1527                _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1528       for (n = 0; n < 3; n++)
1529         {
1530           const gchar *k;
1531           const gchar *v;
1532           switch (n)
1533             {
1534             case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1535             case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1536             case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1537             default: g_assert_not_reached ();
1538             }
1539           v = g_getenv (k);
1540           g_print ("GDBus-debug:Address: env var %s", k);
1541           if (v != NULL)
1542             g_print ("='%s'\n", v);
1543           else
1544             g_print (" is not set\n");
1545         }
1546       _g_dbus_debug_print_unlock ();
1547     }
1548
1549   switch (bus_type)
1550     {
1551     case G_BUS_TYPE_SYSTEM:
1552       ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1553       if (ret == NULL)
1554         {
1555           ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1556         }
1557       break;
1558
1559     case G_BUS_TYPE_SESSION:
1560       ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1561       if (ret == NULL)
1562         {
1563           ret = get_session_address_platform_specific (&local_error);
1564         }
1565       break;
1566
1567     case G_BUS_TYPE_MACHINE:
1568       system_bus = g_getenv ("DBUS_SYSTEM_BUS_ADDRESS");
1569       if (system_bus == NULL)
1570         ret = g_strdup ("kernel:path=/sys/fs/kdbus/0-system/bus;unix:path=/var/run/dbus/system_bus_socket");
1571       else
1572         ret = g_strdup_printf ("kernel:path=/sys/fs/kdbus/0-system/bus;%s", system_bus);
1573       break;
1574
1575     case G_BUS_TYPE_USER:
1576       session_bus = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
1577       if (session_bus == NULL)
1578         ret = g_strdup_printf ("kernel:path=/sys/fs/kdbus/%d-user/bus;%s", getuid(),
1579                                    get_session_address_platform_specific (&local_error));
1580       else
1581         ret = g_strdup_printf ("kernel:path=/sys/fs/kdbus/%d-user/bus;%s", getuid(), session_bus);
1582       break;
1583
1584     case G_BUS_TYPE_STARTER:
1585       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1586       if (g_strcmp0 (starter_bus, "session") == 0)
1587         {
1588           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1589           goto out;
1590         }
1591       else if (g_strcmp0 (starter_bus, "system") == 0)
1592         {
1593           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1594           goto out;
1595         }
1596       else
1597         {
1598           if (starter_bus != NULL)
1599             {
1600               g_set_error (&local_error,
1601                            G_IO_ERROR,
1602                            G_IO_ERROR_FAILED,
1603                            _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1604                              " - unknown value '%s'"),
1605                            starter_bus);
1606             }
1607           else
1608             {
1609               g_set_error_literal (&local_error,
1610                                    G_IO_ERROR,
1611                                    G_IO_ERROR_FAILED,
1612                                    _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1613                                      "variable is not set"));
1614             }
1615         }
1616       break;
1617
1618     default:
1619       g_set_error (&local_error,
1620                    G_IO_ERROR,
1621                    G_IO_ERROR_FAILED,
1622                    _("Unknown bus type %d"),
1623                    bus_type);
1624       break;
1625     }
1626
1627  out:
1628   if (G_UNLIKELY (_g_dbus_debug_address ()))
1629     {
1630       _g_dbus_debug_print_lock ();
1631       if (ret != NULL)
1632         {
1633           g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1634                    ret,
1635                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1636         }
1637       else
1638         {
1639           g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1640                    _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
1641                    local_error ? local_error->message : "");
1642         }
1643       _g_dbus_debug_print_unlock ();
1644     }
1645
1646   if (local_error != NULL)
1647     g_propagate_error (error, local_error);
1648
1649   return ret;
1650 }
1651
1652 /**
1653  * g_dbus_address_escape_value:
1654  * @string: an unescaped string to be included in a D-Bus address
1655  *     as the value in a key-value pair
1656  *
1657  * Escape @string so it can appear in a D-Bus address as the value
1658  * part of a key-value pair.
1659  *
1660  * For instance, if @string is "/run/bus-for-:0",
1661  * this function would return "/run/bus-for-%3A0",
1662  * which could be used in a D-Bus address like
1663  * "unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0".
1664  *
1665  * Returns: (transfer full): a copy of @string with all
1666  *     non-optionally-escaped bytes escaped
1667  *
1668  * Since: 2.36
1669  */
1670 gchar *
1671 g_dbus_address_escape_value (const gchar *string)
1672 {
1673   GString *s;
1674   gsize i;
1675
1676   g_return_val_if_fail (string != NULL, NULL);
1677
1678   /* There will often not be anything needing escaping at all. */
1679   s = g_string_sized_new (strlen (string));
1680
1681   /* D-Bus address escaping is mostly the same as URI escaping... */
1682   g_string_append_uri_escaped (s, string, "\\/", FALSE);
1683
1684   /* ... but '~' is an unreserved character in URIs, but a
1685    * non-optionally-escaped character in D-Bus addresses. */
1686   for (i = 0; i < s->len; i++)
1687     {
1688       if (G_UNLIKELY (s->str[i] == '~'))
1689         {
1690           s->str[i] = '%';
1691           g_string_insert (s, i + 1, "7E");
1692           i += 2;
1693         }
1694     }
1695
1696   return g_string_free (s, FALSE);
1697 }