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