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