GDBus: Add new symbols to gio.symbols
[platform/upstream/glib.git] / gio / gdbusaddress.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2009 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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "gdbusutils.h"
29 #include "gdbusaddress.h"
30 #include "gdbuserror.h"
31 #include "gioenumtypes.h"
32 #include "gdbusprivate.h"
33
34 #ifdef G_OS_UNIX
35 #include <gio/gunixsocketaddress.h>
36 #endif
37
38 #include "glibintl.h"
39 #include "gioalias.h"
40
41 /**
42  * SECTION:gdbusaddress
43  * @title: D-Bus Addresses
44  * @short_description: D-Bus connection endpoints
45  * @include: gio/gio.h
46  *
47  * Routines for working with D-Bus addresses.
48  */
49
50 /* ---------------------------------------------------------------------------------------------------- */
51
52 /**
53  * g_dbus_is_address:
54  * @string: A string.
55  *
56  * Checks if @string is a D-Bus address.
57  *
58  * This doesn't check if @string is actually supported by #GDBusServer
59  * or #GDBusConnection - use g_dbus_is_supported_address() to do more
60  * checks.
61  *
62  * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
63  *
64  * Since: 2.26
65  */
66 gboolean
67 g_dbus_is_address (const gchar *string)
68 {
69   guint n;
70   gchar **a;
71   gboolean ret;
72
73   ret = FALSE;
74
75   g_return_val_if_fail (string != NULL, FALSE);
76
77   a = g_strsplit (string, ";", 0);
78   for (n = 0; a[n] != NULL; n++)
79     {
80       if (!_g_dbus_address_parse_entry (a[n],
81                                         NULL,
82                                         NULL,
83                                         NULL))
84         goto out;
85     }
86
87   ret = TRUE;
88
89  out:
90   g_strfreev (a);
91   return ret;
92 }
93
94 static gboolean
95 is_valid_unix (const gchar  *address_entry,
96                GHashTable   *key_value_pairs,
97                GError      **error)
98 {
99   gboolean ret;
100   GList *keys;
101   GList *l;
102   const gchar *path;
103   const gchar *tmpdir;
104   const gchar *abstract;
105
106   ret = FALSE;
107   keys = NULL;
108   path = NULL;
109   tmpdir = NULL;
110   abstract = NULL;
111
112   keys = g_hash_table_get_keys (key_value_pairs);
113   for (l = keys; l != NULL; l = l->next)
114     {
115       const gchar *key = l->data;
116       if (g_strcmp0 (key, "path") == 0)
117         path = g_hash_table_lookup (key_value_pairs, key);
118       else if (g_strcmp0 (key, "tmpdir") == 0)
119         tmpdir = g_hash_table_lookup (key_value_pairs, key);
120       else if (g_strcmp0 (key, "abstract") == 0)
121         abstract = g_hash_table_lookup (key_value_pairs, key);
122       else
123         {
124           g_set_error (error,
125                        G_IO_ERROR,
126                        G_IO_ERROR_INVALID_ARGUMENT,
127                        _("Unsupported key `%s' in address entry `%s'"),
128                        key,
129                        address_entry);
130           goto out;
131         }
132     }
133
134   if (path != NULL)
135     {
136       if (tmpdir != NULL || abstract != NULL)
137         goto meaningless;
138       /* TODO: validate path */
139     }
140   else if (tmpdir != NULL)
141     {
142       if (path != NULL || abstract != NULL)
143         goto meaningless;
144       /* TODO: validate tmpdir */
145     }
146   else if (abstract != NULL)
147     {
148       if (path != NULL || tmpdir != NULL)
149         goto meaningless;
150       /* TODO: validate abstract */
151     }
152   else
153     {
154       g_set_error (error,
155                    G_IO_ERROR,
156                    G_IO_ERROR_INVALID_ARGUMENT,
157                    _("Address `%s' is invalid (need exactly one of path, tmpdir or abstract keys"),
158                    address_entry);
159       goto out;
160     }
161
162
163   ret= TRUE;
164   goto out;
165
166  meaningless:
167   g_set_error (error,
168                G_IO_ERROR,
169                G_IO_ERROR_INVALID_ARGUMENT,
170                _("Meaningless key/value pair combination in address entry `%s'"),
171                address_entry);
172
173  out:
174   g_list_free (keys);
175
176   return ret;
177 }
178
179 static gboolean
180 is_valid_nonce_tcp (const gchar  *address_entry,
181                     GHashTable   *key_value_pairs,
182                     GError      **error)
183 {
184   gboolean ret;
185   GList *keys;
186   GList *l;
187   const gchar *host;
188   const gchar *port;
189   const gchar *family;
190   const gchar *nonce_file;
191   gint port_num;
192   gchar *endp;
193
194   ret = FALSE;
195   keys = NULL;
196   host = NULL;
197   port = NULL;
198   family = NULL;
199   nonce_file = NULL;
200
201   keys = g_hash_table_get_keys (key_value_pairs);
202   for (l = keys; l != NULL; l = l->next)
203     {
204       const gchar *key = l->data;
205       if (g_strcmp0 (key, "host") == 0)
206         host = g_hash_table_lookup (key_value_pairs, key);
207       else if (g_strcmp0 (key, "port") == 0)
208         port = g_hash_table_lookup (key_value_pairs, key);
209       else if (g_strcmp0 (key, "family") == 0)
210         family = g_hash_table_lookup (key_value_pairs, key);
211       else if (g_strcmp0 (key, "noncefile") == 0)
212         nonce_file = g_hash_table_lookup (key_value_pairs, key);
213       else
214         {
215           g_set_error (error,
216                        G_IO_ERROR,
217                        G_IO_ERROR_INVALID_ARGUMENT,
218                        _("Unsupported key `%s' in address entry `%s'"),
219                        key,
220                        address_entry);
221           goto out;
222         }
223     }
224
225   if (port != NULL)
226     {
227       port_num = strtol (port, &endp, 10);
228       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
229         {
230           g_set_error (error,
231                        G_IO_ERROR,
232                        G_IO_ERROR_INVALID_ARGUMENT,
233                        _("Error in address `%s' - the port attribute is malformed"),
234                        address_entry);
235           goto out;
236         }
237     }
238
239   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
240     {
241       g_set_error (error,
242                    G_IO_ERROR,
243                    G_IO_ERROR_INVALID_ARGUMENT,
244                    _("Error in address `%s' - the family attribute is malformed"),
245                    address_entry);
246       goto out;
247     }
248
249   ret= TRUE;
250
251  out:
252   g_list_free (keys);
253
254   return ret;
255 }
256
257 static gboolean
258 is_valid_tcp (const gchar  *address_entry,
259               GHashTable   *key_value_pairs,
260               GError      **error)
261 {
262   gboolean ret;
263   GList *keys;
264   GList *l;
265   const gchar *host;
266   const gchar *port;
267   const gchar *family;
268   gint port_num;
269   gchar *endp;
270
271   ret = FALSE;
272   keys = NULL;
273   host = NULL;
274   port = NULL;
275   family = NULL;
276
277   keys = g_hash_table_get_keys (key_value_pairs);
278   for (l = keys; l != NULL; l = l->next)
279     {
280       const gchar *key = l->data;
281       if (g_strcmp0 (key, "host") == 0)
282         host = g_hash_table_lookup (key_value_pairs, key);
283       else if (g_strcmp0 (key, "port") == 0)
284         port = g_hash_table_lookup (key_value_pairs, key);
285       else if (g_strcmp0 (key, "family") == 0)
286         family = g_hash_table_lookup (key_value_pairs, key);
287       else
288         {
289           g_set_error (error,
290                        G_IO_ERROR,
291                        G_IO_ERROR_INVALID_ARGUMENT,
292                        _("Unsupported key `%s' in address entry `%s'"),
293                        key,
294                        address_entry);
295           goto out;
296         }
297     }
298
299   if (port != NULL)
300     {
301       port_num = strtol (port, &endp, 10);
302       if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
303         {
304           g_set_error (error,
305                        G_IO_ERROR,
306                        G_IO_ERROR_INVALID_ARGUMENT,
307                        _("Error in address `%s' - the port attribute is malformed"),
308                        address_entry);
309           goto out;
310         }
311     }
312
313   if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
314     {
315       g_set_error (error,
316                    G_IO_ERROR,
317                    G_IO_ERROR_INVALID_ARGUMENT,
318                    _("Error in address `%s' - the family attribute is malformed"),
319                    address_entry);
320       goto out;
321     }
322
323   ret= TRUE;
324
325  out:
326   g_list_free (keys);
327
328   return ret;
329 }
330
331 /**
332  * g_dbus_is_supported_address:
333  * @string: A string.
334  * @error: Return location for error or %NULL.
335  *
336  * Like g_dbus_is_address() but also checks if the library suppors the
337  * transports in @string and that key/value pairs for each transport
338  * are valid.
339  *
340  * Returns: %TRUE if @string is a valid D-Bus address that is
341  * supported by this library, %FALSE if @error is set.
342  *
343  * Since: 2.26
344  */
345 gboolean
346 g_dbus_is_supported_address (const gchar  *string,
347                              GError      **error)
348 {
349   guint n;
350   gchar **a;
351   gboolean ret;
352
353   ret = FALSE;
354
355   g_return_val_if_fail (string != NULL, FALSE);
356   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
357
358   a = g_strsplit (string, ";", 0);
359   for (n = 0; a[n] != NULL; n++)
360     {
361       gchar *transport_name;
362       GHashTable *key_value_pairs;
363       gboolean supported;
364
365       if (!_g_dbus_address_parse_entry (a[n],
366                                         &transport_name,
367                                         &key_value_pairs,
368                                         error))
369         goto out;
370
371       supported = FALSE;
372       if (g_strcmp0 (transport_name, "unix") == 0)
373         supported = is_valid_unix (a[n], key_value_pairs, error);
374       else if (g_strcmp0 (transport_name, "tcp") == 0)
375         supported = is_valid_tcp (a[n], key_value_pairs, error);
376       else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
377         supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
378
379       g_free (transport_name);
380       g_hash_table_unref (key_value_pairs);
381
382       if (!supported)
383         goto out;
384     }
385
386   ret = TRUE;
387
388  out:
389   g_strfreev (a);
390
391   g_assert (ret || (!ret && (error == NULL || *error != NULL)));
392
393   return ret;
394 }
395
396 gboolean
397 _g_dbus_address_parse_entry (const gchar   *address_entry,
398                              gchar        **out_transport_name,
399                              GHashTable   **out_key_value_pairs,
400                              GError       **error)
401 {
402   gboolean ret;
403   GHashTable *key_value_pairs;
404   gchar *transport_name;
405   gchar **kv_pairs;
406   const gchar *s;
407   guint n;
408
409   ret = FALSE;
410   kv_pairs = NULL;
411   transport_name = NULL;
412   key_value_pairs = NULL;
413
414   s = strchr (address_entry, ':');
415   if (s == NULL)
416     {
417       g_set_error (error,
418                    G_IO_ERROR,
419                    G_IO_ERROR_INVALID_ARGUMENT,
420                    _("Address element `%s', does not contain a colon (:)"),
421                    address_entry);
422       goto out;
423     }
424
425   transport_name = g_strndup (address_entry, s - address_entry);
426   key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
427
428   kv_pairs = g_strsplit (s + 1, ",", 0);
429   for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
430     {
431       const gchar *kv_pair = kv_pairs[n];
432       gchar *key;
433       gchar *value;
434
435       s = strchr (kv_pair, '=');
436       if (s == NULL)
437         {
438           g_set_error (error,
439                        G_IO_ERROR,
440                        G_IO_ERROR_INVALID_ARGUMENT,
441                        _("Key/Value pair %d, `%s', in address element `%s', does not contain an equal sign"),
442                        n,
443                        kv_pair,
444                        address_entry);
445           goto out;
446         }
447
448       /* TODO: actually validate that no illegal characters are present before and after then '=' sign */
449       key = g_uri_unescape_segment (kv_pair, s, NULL);
450       value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
451       g_hash_table_insert (key_value_pairs, key, value);
452     }
453
454   ret = TRUE;
455
456 out:
457   g_strfreev (kv_pairs);
458   if (ret)
459     {
460       if (out_transport_name != NULL)
461         *out_transport_name = transport_name;
462       else
463         g_free (transport_name);
464       if (out_key_value_pairs != NULL)
465         *out_key_value_pairs = key_value_pairs;
466       else if (key_value_pairs != NULL)
467         g_hash_table_unref (key_value_pairs);
468     }
469   else
470     {
471       g_free (transport_name);
472       if (key_value_pairs != NULL)
473         g_hash_table_unref (key_value_pairs);
474     }
475   return ret;
476 }
477
478 /* ---------------------------------------------------------------------------------------------------- */
479
480 /* TODO: Declare an extension point called GDBusTransport (or similar)
481  * and move code below to extensions implementing said extension
482  * point. That way we can implement a D-Bus transport over X11 without
483  * making libgio link to libX11...
484  */
485 static GIOStream *
486 g_dbus_address_connect (const gchar    *address_entry,
487                         const gchar    *transport_name,
488                         GHashTable     *key_value_pairs,
489                         GCancellable   *cancellable,
490                         GError        **error)
491 {
492   GIOStream *ret;
493   GSocketConnectable *connectable;
494   const gchar *nonce_file;
495
496   connectable = NULL;
497   ret = NULL;
498   nonce_file = NULL;
499
500   if (FALSE)
501     {
502     }
503 #ifdef G_OS_UNIX
504   else if (g_strcmp0 (transport_name, "unix") == 0)
505     {
506       const gchar *path;
507       const gchar *abstract;
508       path = g_hash_table_lookup (key_value_pairs, "path");
509       abstract = g_hash_table_lookup (key_value_pairs, "abstract");
510       if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
511         {
512           g_set_error (error,
513                        G_IO_ERROR,
514                        G_IO_ERROR_INVALID_ARGUMENT,
515                        _("Error in address `%s' - the unix transport requires exactly one of the "
516                          "keys `path' or `abstract' to be set"),
517                        address_entry);
518         }
519       else if (path != NULL)
520         {
521           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
522         }
523       else if (abstract != NULL)
524         {
525           connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
526                                                                                    -1,
527                                                                                    G_UNIX_SOCKET_ADDRESS_ABSTRACT));
528         }
529       else
530         {
531           g_assert_not_reached ();
532         }
533     }
534 #endif
535   else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
536     {
537       const gchar *s;
538       const gchar *host;
539       guint port;
540       gchar *endp;
541       gboolean is_nonce;
542
543       is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
544
545       host = g_hash_table_lookup (key_value_pairs, "host");
546       if (host == NULL)
547         {
548           g_set_error (error,
549                        G_IO_ERROR,
550                        G_IO_ERROR_INVALID_ARGUMENT,
551                        _("Error in address `%s' - the host attribute is missing or malformed"),
552                        address_entry);
553           goto out;
554         }
555
556       s = g_hash_table_lookup (key_value_pairs, "port");
557       if (s == NULL)
558         s = "0";
559       port = strtol (s, &endp, 10);
560       if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
561         {
562           g_set_error (error,
563                        G_IO_ERROR,
564                        G_IO_ERROR_INVALID_ARGUMENT,
565                        _("Error in address `%s' - the port attribute is missing or malformed"),
566                        address_entry);
567           goto out;
568         }
569
570
571       if (is_nonce)
572         {
573           nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
574           if (nonce_file == NULL)
575             {
576               g_set_error (error,
577                            G_IO_ERROR,
578                            G_IO_ERROR_INVALID_ARGUMENT,
579                            _("Error in address `%s' - the noncefile attribute is missing or malformed"),
580                            address_entry);
581               goto out;
582             }
583         }
584
585       /* TODO: deal with family */
586       connectable = g_network_address_new (host, port);
587     }
588   else
589     {
590       g_set_error (error,
591                    G_IO_ERROR,
592                    G_IO_ERROR_INVALID_ARGUMENT,
593                    _("Unknown or unsupported transport `%s' for address `%s'"),
594                    transport_name,
595                    address_entry);
596     }
597
598   if (connectable != NULL)
599     {
600       GSocketClient *client;
601       GSocketConnection *connection;
602
603       g_assert (ret == NULL);
604       client = g_socket_client_new ();
605       connection = g_socket_client_connect (client,
606                                             connectable,
607                                             cancellable,
608                                             error);
609       g_object_unref (connectable);
610       g_object_unref (client);
611       if (connection == NULL)
612         goto out;
613
614       ret = G_IO_STREAM (connection);
615
616       if (nonce_file != NULL)
617         {
618           gchar *nonce_contents;
619           gsize nonce_length;
620
621           /* TODO: too dangerous to read the entire file? (think denial-of-service etc.) */
622           if (!g_file_get_contents (nonce_file,
623                                     &nonce_contents,
624                                     &nonce_length,
625                                     error))
626             {
627               g_prefix_error (error, _("Error reading nonce file `%s':"), nonce_file);
628               g_object_unref (ret);
629               ret = NULL;
630               goto out;
631             }
632
633           if (nonce_length != 16)
634             {
635               g_set_error (error,
636                            G_IO_ERROR,
637                            G_IO_ERROR_INVALID_ARGUMENT,
638                            _("The nonce-file `%s' was %" G_GSIZE_FORMAT " bytes. Expected 16 bytes."),
639                            nonce_file,
640                            nonce_length);
641               g_free (nonce_contents);
642               g_object_unref (ret);
643               ret = NULL;
644               goto out;
645             }
646
647           if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
648                                           nonce_contents,
649                                           nonce_length,
650                                           NULL,
651                                           cancellable,
652                                           error))
653             {
654               g_prefix_error (error, _("Error write contents of nonce file `%s' to stream:"), nonce_file);
655               g_object_unref (ret);
656               ret = NULL;
657               g_free (nonce_contents);
658               goto out;
659             }
660           g_free (nonce_contents);
661         }
662     }
663
664  out:
665
666   return ret;
667 }
668
669 static GIOStream *
670 g_dbus_address_try_connect_one (const gchar         *address_entry,
671                                 gchar              **out_guid,
672                                 GCancellable        *cancellable,
673                                 GError             **error)
674 {
675   GIOStream *ret;
676   GHashTable *key_value_pairs;
677   gchar *transport_name;
678   const gchar *guid;
679
680   ret = NULL;
681   transport_name = NULL;
682   key_value_pairs = NULL;
683
684   if (!_g_dbus_address_parse_entry (address_entry,
685                                     &transport_name,
686                                     &key_value_pairs,
687                                     error))
688     goto out;
689
690   ret = g_dbus_address_connect (address_entry,
691                                 transport_name,
692                                 key_value_pairs,
693                                 cancellable,
694                                 error);
695   if (ret == NULL)
696     goto out;
697
698   /* TODO: validate that guid is of correct format */
699   guid = g_hash_table_lookup (key_value_pairs, "guid");
700   if (guid != NULL && out_guid != NULL)
701     *out_guid = g_strdup (guid);
702
703 out:
704   g_free (transport_name);
705   if (key_value_pairs != NULL)
706     g_hash_table_unref (key_value_pairs);
707   return ret;
708 }
709
710
711 /* ---------------------------------------------------------------------------------------------------- */
712
713 typedef struct {
714   gchar *address;
715   GIOStream *stream;
716   gchar *guid;
717 } GetStreamData;
718
719 static void
720 get_stream_data_free (GetStreamData *data)
721 {
722   g_free (data->address);
723   if (data->stream != NULL)
724     g_object_unref (data->stream);
725   g_free (data->guid);
726   g_free (data);
727 }
728
729 static void
730 get_stream_thread_func (GSimpleAsyncResult *res,
731                         GObject            *object,
732                         GCancellable       *cancellable)
733 {
734   GetStreamData *data;
735   GError *error;
736
737   data = g_simple_async_result_get_op_res_gpointer (res);
738
739   error = NULL;
740   data->stream = g_dbus_address_get_stream_sync (data->address,
741                                                  &data->guid,
742                                                  cancellable,
743                                                  &error);
744   if (data->stream == NULL)
745     {
746       g_simple_async_result_set_from_error (res, error);
747       g_error_free (error);
748     }
749 }
750
751 /**
752  * g_dbus_address_get_stream:
753  * @address: A valid D-Bus address.
754  * @cancellable: A #GCancellable or %NULL.
755  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
756  * @user_data: Data to pass to @callback.
757  *
758  * Asynchronously connects to an endpoint specified by @address and
759  * sets up the connection so it is in a state to run the client-side
760  * of the D-Bus authentication conversation.
761  *
762  * When the operation is finished, @callback will be invoked. You can
763  * then call g_dbus_address_get_stream_finish() to get the result of
764  * the operation.
765  *
766  * This is an asynchronous failable function. See
767  * g_dbus_address_get_stream_sync() for the synchronous version.
768  *
769  * Since: 2.26
770  */
771 void
772 g_dbus_address_get_stream (const gchar         *address,
773                            GCancellable        *cancellable,
774                            GAsyncReadyCallback  callback,
775                            gpointer             user_data)
776 {
777   GSimpleAsyncResult *res;
778   GetStreamData *data;
779
780   g_return_if_fail (address != NULL);
781
782   res = g_simple_async_result_new (NULL,
783                                    callback,
784                                    user_data,
785                                    g_dbus_address_get_stream);
786   data = g_new0 (GetStreamData, 1);
787   data->address = g_strdup (address);
788   g_simple_async_result_set_op_res_gpointer (res,
789                                              data,
790                                              (GDestroyNotify) get_stream_data_free);
791   g_simple_async_result_run_in_thread (res,
792                                        get_stream_thread_func,
793                                        G_PRIORITY_DEFAULT,
794                                        cancellable);
795   g_object_unref (res);
796 }
797
798 /**
799  * g_dbus_address_get_stream_finish:
800  * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
801  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
802  * @error: Return location for error or %NULL.
803  *
804  * Finishes an operation started with g_dbus_address_get_stream().
805  *
806  * Returns: A #GIOStream or %NULL if @error is set.
807  *
808  * Since: 2.26
809  */
810 GIOStream *
811 g_dbus_address_get_stream_finish (GAsyncResult        *res,
812                                   gchar              **out_guid,
813                                   GError             **error)
814 {
815   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
816   GetStreamData *data;
817   GIOStream *ret;
818
819   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
820   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
821
822   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
823
824   ret = NULL;
825
826   data = g_simple_async_result_get_op_res_gpointer (simple);
827   if (g_simple_async_result_propagate_error (simple, error))
828     goto out;
829
830   ret = g_object_ref (data->stream);
831   if (out_guid != NULL)
832     *out_guid = g_strdup (data->guid);
833
834  out:
835   return ret;
836 }
837
838 /**
839  * g_dbus_address_get_stream_sync:
840  * @address: A valid D-Bus address.
841  * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
842  * @cancellable: A #GCancellable or %NULL.
843  * @error: Return location for error or %NULL.
844  *
845  * Synchronously connects to an endpoint specified by @address and
846  * sets up the connection so it is in a state to run the client-side
847  * of the D-Bus authentication conversation.
848  *
849  * This is a synchronous failable function. See
850  * g_dbus_address_get_stream() for the asynchronous version.
851  *
852  * Returns: A #GIOStream or %NULL if @error is set.
853  *
854  * Since: 2.26
855  */
856 GIOStream *
857 g_dbus_address_get_stream_sync (const gchar         *address,
858                                 gchar              **out_guid,
859                                 GCancellable        *cancellable,
860                                 GError             **error)
861 {
862   GIOStream *ret;
863   gchar **addr_array;
864   guint n;
865   GError *last_error;
866
867   g_return_val_if_fail (address != NULL, NULL);
868   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
869
870   ret = NULL;
871   last_error = NULL;
872
873   addr_array = g_strsplit (address, ";", 0);
874   last_error = NULL;
875   for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
876     {
877       const gchar *addr = addr_array[n];
878       GError *this_error;
879       this_error = NULL;
880       ret = g_dbus_address_try_connect_one (addr,
881                                             out_guid,
882                                             cancellable,
883                                             &this_error);
884       if (ret != NULL)
885         {
886           goto out;
887         }
888       else
889         {
890           g_assert (this_error != NULL);
891           if (last_error != NULL)
892             g_error_free (last_error);
893           last_error = this_error;
894         }
895     }
896
897  out:
898   if (ret != NULL)
899     {
900       if (last_error != NULL)
901         g_error_free (last_error);
902     }
903   else
904     {
905       g_assert (last_error != NULL);
906       g_propagate_error (error, last_error);
907     }
908   return ret;
909 }
910
911 /* ---------------------------------------------------------------------------------------------------- */
912
913 /* TODO: implement for UNIX, Win32 and OS X */
914 static gchar *
915 get_session_address_platform_specific (void)
916 {
917   return NULL;
918 }
919
920 /* ---------------------------------------------------------------------------------------------------- */
921
922 /**
923  * g_dbus_address_get_for_bus_sync:
924  * @bus_type: A #GBusType.
925  * @cancellable: A #GCancellable or %NULL.
926  * @error: Return location for error or %NULL.
927  *
928  * Synchronously looks up the D-Bus address for the well-known message
929  * bus instance specified by @bus_type. This may involve using various
930  * platform specific mechanisms.
931  *
932  * Returns: A valid D-Bus address string for @bus_type or %NULL if @error is set.
933  *
934  * Since: 2.26
935  */
936 gchar *
937 g_dbus_address_get_for_bus_sync (GBusType       bus_type,
938                                  GCancellable  *cancellable,
939                                  GError       **error)
940 {
941   gchar *ret;
942   const gchar *starter_bus;
943
944   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
945
946   ret = NULL;
947
948   switch (bus_type)
949     {
950     case G_BUS_TYPE_SYSTEM:
951       ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
952       if (ret == NULL)
953         {
954           ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
955         }
956       break;
957
958     case G_BUS_TYPE_SESSION:
959       ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
960       if (ret == NULL)
961         {
962           ret = get_session_address_platform_specific ();
963           if (ret == NULL)
964             {
965               g_set_error (error,
966                            G_IO_ERROR,
967                            G_IO_ERROR_FAILED,
968                            _("Cannot determine session bus address (TODO: run dbus-launch to find out)"));
969             }
970         }
971       break;
972
973     case G_BUS_TYPE_STARTER:
974       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
975       if (g_strcmp0 (starter_bus, "session") == 0)
976         {
977           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, error);
978           goto out;
979         }
980       else if (g_strcmp0 (starter_bus, "system") == 0)
981         {
982           ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
983           goto out;
984         }
985       else
986         {
987           if (starter_bus != NULL)
988             {
989               g_set_error (error,
990                            G_IO_ERROR,
991                            G_IO_ERROR_FAILED,
992                            _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
993                              " - unknown value `%s'"),
994                            starter_bus);
995             }
996           else
997             {
998               g_set_error_literal (error,
999                                    G_IO_ERROR,
1000                                    G_IO_ERROR_FAILED,
1001                                    _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1002                                      "variable is not set"));
1003             }
1004         }
1005       break;
1006
1007     default:
1008       g_set_error (error,
1009                    G_IO_ERROR,
1010                    G_IO_ERROR_FAILED,
1011                    _("Unknown bus type %d"),
1012                    bus_type);
1013       break;
1014     }
1015
1016  out:
1017   return ret;
1018 }
1019
1020 #define __G_DBUS_ADDRESS_C__
1021 #include "gioaliasdef.c"