Better documentation for g_value_dup_object().
[glib.git] / gio / gdbusaddress.c
blob83e76998e94ba5317ab595ed6ecfd496b936fc47
1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: David Zeuthen <davidz@redhat.com>
23 #include "config.h"
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <errno.h>
30 #include "gioerror.h"
31 #include "gdbusutils.h"
32 #include "gdbusaddress.h"
33 #include "gdbuserror.h"
34 #include "gioenumtypes.h"
35 #include "gnetworkaddress.h"
36 #include "gsocketclient.h"
37 #include "giostream.h"
38 #include "gasyncresult.h"
39 #include "gsimpleasyncresult.h"
40 #include "gdbusprivate.h"
42 #ifdef G_OS_UNIX
43 #include <gio/gunixsocketaddress.h>
44 #include <sys/wait.h>
45 #endif
47 #include "glibintl.h"
49 /**
50 * SECTION:gdbusaddress
51 * @title: D-Bus Addresses
52 * @short_description: D-Bus connection endpoints
53 * @include: gio/gio.h
55 * Routines for working with D-Bus addresses. A D-Bus address is a string
56 * like "unix:tmpdir=/tmp/my-app-name". The exact format of addresses
57 * is explained in detail in the <link linkend="http://dbus.freedesktop.org/doc/dbus-specification.html&num;addresses">D-Bus specification</link>.
60 static gchar *get_session_address_platform_specific (GError **error);
62 /* ---------------------------------------------------------------------------------------------------- */
64 /**
65 * g_dbus_is_address:
66 * @string: A string.
68 * Checks if @string is a D-Bus address.
70 * This doesn't check if @string is actually supported by #GDBusServer
71 * or #GDBusConnection - use g_dbus_is_supported_address() to do more
72 * checks.
74 * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
76 * Since: 2.26
78 gboolean
79 g_dbus_is_address (const gchar *string)
81 guint n;
82 gchar **a;
83 gboolean ret;
85 ret = FALSE;
87 g_return_val_if_fail (string != NULL, FALSE);
89 a = g_strsplit (string, ";", 0);
90 if (a[0] == NULL)
91 goto out;
93 for (n = 0; a[n] != NULL; n++)
95 if (!_g_dbus_address_parse_entry (a[n],
96 NULL,
97 NULL,
98 NULL))
99 goto out;
102 ret = TRUE;
104 out:
105 g_strfreev (a);
106 return ret;
109 static gboolean
110 is_valid_unix (const gchar *address_entry,
111 GHashTable *key_value_pairs,
112 GError **error)
114 gboolean ret;
115 GList *keys;
116 GList *l;
117 const gchar *path;
118 const gchar *tmpdir;
119 const gchar *abstract;
121 ret = FALSE;
122 keys = NULL;
123 path = NULL;
124 tmpdir = NULL;
125 abstract = NULL;
127 keys = g_hash_table_get_keys (key_value_pairs);
128 for (l = keys; l != NULL; l = l->next)
130 const gchar *key = l->data;
131 if (g_strcmp0 (key, "path") == 0)
132 path = g_hash_table_lookup (key_value_pairs, key);
133 else if (g_strcmp0 (key, "tmpdir") == 0)
134 tmpdir = g_hash_table_lookup (key_value_pairs, key);
135 else if (g_strcmp0 (key, "abstract") == 0)
136 abstract = g_hash_table_lookup (key_value_pairs, key);
137 else
139 g_set_error (error,
140 G_IO_ERROR,
141 G_IO_ERROR_INVALID_ARGUMENT,
142 _("Unsupported key `%s' in address entry `%s'"),
143 key,
144 address_entry);
145 goto out;
149 if (path != NULL)
151 if (tmpdir != NULL || abstract != NULL)
152 goto meaningless;
154 else if (tmpdir != NULL)
156 if (path != NULL || abstract != NULL)
157 goto meaningless;
159 else if (abstract != NULL)
161 if (path != NULL || tmpdir != NULL)
162 goto meaningless;
164 else
166 g_set_error (error,
167 G_IO_ERROR,
168 G_IO_ERROR_INVALID_ARGUMENT,
169 _("Address `%s' is invalid (need exactly one of path, tmpdir or abstract keys)"),
170 address_entry);
171 goto out;
175 ret= TRUE;
176 goto out;
178 meaningless:
179 g_set_error (error,
180 G_IO_ERROR,
181 G_IO_ERROR_INVALID_ARGUMENT,
182 _("Meaningless key/value pair combination in address entry `%s'"),
183 address_entry);
185 out:
186 g_list_free (keys);
188 return ret;
191 static gboolean
192 is_valid_nonce_tcp (const gchar *address_entry,
193 GHashTable *key_value_pairs,
194 GError **error)
196 gboolean ret;
197 GList *keys;
198 GList *l;
199 const gchar *host;
200 const gchar *port;
201 const gchar *family;
202 const gchar *nonce_file;
203 gint port_num;
204 gchar *endp;
206 ret = FALSE;
207 keys = NULL;
208 host = NULL;
209 port = NULL;
210 family = NULL;
211 nonce_file = NULL;
213 keys = g_hash_table_get_keys (key_value_pairs);
214 for (l = keys; l != NULL; l = l->next)
216 const gchar *key = l->data;
217 if (g_strcmp0 (key, "host") == 0)
218 host = g_hash_table_lookup (key_value_pairs, key);
219 else if (g_strcmp0 (key, "port") == 0)
220 port = g_hash_table_lookup (key_value_pairs, key);
221 else if (g_strcmp0 (key, "family") == 0)
222 family = g_hash_table_lookup (key_value_pairs, key);
223 else if (g_strcmp0 (key, "noncefile") == 0)
224 nonce_file = g_hash_table_lookup (key_value_pairs, key);
225 else
227 g_set_error (error,
228 G_IO_ERROR,
229 G_IO_ERROR_INVALID_ARGUMENT,
230 _("Unsupported key `%s' in address entry `%s'"),
231 key,
232 address_entry);
233 goto out;
237 if (port != NULL)
239 port_num = strtol (port, &endp, 10);
240 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
242 g_set_error (error,
243 G_IO_ERROR,
244 G_IO_ERROR_INVALID_ARGUMENT,
245 _("Error in address `%s' - the port attribute is malformed"),
246 address_entry);
247 goto out;
251 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
253 g_set_error (error,
254 G_IO_ERROR,
255 G_IO_ERROR_INVALID_ARGUMENT,
256 _("Error in address `%s' - the family attribute is malformed"),
257 address_entry);
258 goto out;
261 ret= TRUE;
263 out:
264 g_list_free (keys);
266 return ret;
269 static gboolean
270 is_valid_tcp (const gchar *address_entry,
271 GHashTable *key_value_pairs,
272 GError **error)
274 gboolean ret;
275 GList *keys;
276 GList *l;
277 const gchar *host;
278 const gchar *port;
279 const gchar *family;
280 gint port_num;
281 gchar *endp;
283 ret = FALSE;
284 keys = NULL;
285 host = NULL;
286 port = NULL;
287 family = NULL;
289 keys = g_hash_table_get_keys (key_value_pairs);
290 for (l = keys; l != NULL; l = l->next)
292 const gchar *key = l->data;
293 if (g_strcmp0 (key, "host") == 0)
294 host = g_hash_table_lookup (key_value_pairs, key);
295 else if (g_strcmp0 (key, "port") == 0)
296 port = g_hash_table_lookup (key_value_pairs, key);
297 else if (g_strcmp0 (key, "family") == 0)
298 family = g_hash_table_lookup (key_value_pairs, key);
299 else
301 g_set_error (error,
302 G_IO_ERROR,
303 G_IO_ERROR_INVALID_ARGUMENT,
304 _("Unsupported key `%s' in address entry `%s'"),
305 key,
306 address_entry);
307 goto out;
311 if (port != NULL)
313 port_num = strtol (port, &endp, 10);
314 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
316 g_set_error (error,
317 G_IO_ERROR,
318 G_IO_ERROR_INVALID_ARGUMENT,
319 _("Error in address `%s' - the port attribute is malformed"),
320 address_entry);
321 goto out;
325 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
327 g_set_error (error,
328 G_IO_ERROR,
329 G_IO_ERROR_INVALID_ARGUMENT,
330 _("Error in address `%s' - the family attribute is malformed"),
331 address_entry);
332 goto out;
335 ret= TRUE;
337 out:
338 g_list_free (keys);
340 return ret;
344 * g_dbus_is_supported_address:
345 * @string: A string.
346 * @error: Return location for error or %NULL.
348 * Like g_dbus_is_address() but also checks if the library suppors the
349 * transports in @string and that key/value pairs for each transport
350 * are valid.
352 * Returns: %TRUE if @string is a valid D-Bus address that is
353 * supported by this library, %FALSE if @error is set.
355 * Since: 2.26
357 gboolean
358 g_dbus_is_supported_address (const gchar *string,
359 GError **error)
361 guint n;
362 gchar **a;
363 gboolean ret;
365 ret = FALSE;
367 g_return_val_if_fail (string != NULL, FALSE);
368 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
370 a = g_strsplit (string, ";", 0);
371 for (n = 0; a[n] != NULL; n++)
373 gchar *transport_name;
374 GHashTable *key_value_pairs;
375 gboolean supported;
377 if (!_g_dbus_address_parse_entry (a[n],
378 &transport_name,
379 &key_value_pairs,
380 error))
381 goto out;
383 supported = FALSE;
384 if (g_strcmp0 (transport_name, "unix") == 0)
385 supported = is_valid_unix (a[n], key_value_pairs, error);
386 else if (g_strcmp0 (transport_name, "tcp") == 0)
387 supported = is_valid_tcp (a[n], key_value_pairs, error);
388 else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
389 supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
390 else if (g_strcmp0 (a[n], "autolaunch:") == 0)
391 supported = TRUE;
393 g_free (transport_name);
394 g_hash_table_unref (key_value_pairs);
396 if (!supported)
397 goto out;
400 ret = TRUE;
402 out:
403 g_strfreev (a);
405 g_assert (ret || (!ret && (error == NULL || *error != NULL)));
407 return ret;
410 gboolean
411 _g_dbus_address_parse_entry (const gchar *address_entry,
412 gchar **out_transport_name,
413 GHashTable **out_key_value_pairs,
414 GError **error)
416 gboolean ret;
417 GHashTable *key_value_pairs;
418 gchar *transport_name;
419 gchar **kv_pairs;
420 const gchar *s;
421 guint n;
423 ret = FALSE;
424 kv_pairs = NULL;
425 transport_name = NULL;
426 key_value_pairs = NULL;
428 s = strchr (address_entry, ':');
429 if (s == NULL)
431 g_set_error (error,
432 G_IO_ERROR,
433 G_IO_ERROR_INVALID_ARGUMENT,
434 _("Address element `%s', does not contain a colon (:)"),
435 address_entry);
436 goto out;
439 transport_name = g_strndup (address_entry, s - address_entry);
440 key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
442 kv_pairs = g_strsplit (s + 1, ",", 0);
443 for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
445 const gchar *kv_pair = kv_pairs[n];
446 gchar *key;
447 gchar *value;
449 s = strchr (kv_pair, '=');
450 if (s == NULL)
452 g_set_error (error,
453 G_IO_ERROR,
454 G_IO_ERROR_INVALID_ARGUMENT,
455 _("Key/Value pair %d, `%s', in address element `%s', does not contain an equal sign"),
457 kv_pair,
458 address_entry);
459 goto out;
462 key = g_uri_unescape_segment (kv_pair, s, NULL);
463 value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
464 if (key == NULL || value == NULL)
466 g_set_error (error,
467 G_IO_ERROR,
468 G_IO_ERROR_INVALID_ARGUMENT,
469 _("Error unescaping key or value in Key/Value pair %d, `%s', in address element `%s'"),
471 kv_pair,
472 address_entry);
473 g_free (key);
474 g_free (value);
475 goto out;
477 g_hash_table_insert (key_value_pairs, key, value);
480 ret = TRUE;
482 out:
483 g_strfreev (kv_pairs);
484 if (ret)
486 if (out_transport_name != NULL)
487 *out_transport_name = transport_name;
488 else
489 g_free (transport_name);
490 if (out_key_value_pairs != NULL)
491 *out_key_value_pairs = key_value_pairs;
492 else if (key_value_pairs != NULL)
493 g_hash_table_unref (key_value_pairs);
495 else
497 g_free (transport_name);
498 if (key_value_pairs != NULL)
499 g_hash_table_unref (key_value_pairs);
501 return ret;
504 /* ---------------------------------------------------------------------------------------------------- */
506 static GIOStream *
507 g_dbus_address_try_connect_one (const gchar *address_entry,
508 gchar **out_guid,
509 GCancellable *cancellable,
510 GError **error);
512 /* TODO: Declare an extension point called GDBusTransport (or similar)
513 * and move code below to extensions implementing said extension
514 * point. That way we can implement a D-Bus transport over X11 without
515 * making libgio link to libX11...
517 static GIOStream *
518 g_dbus_address_connect (const gchar *address_entry,
519 const gchar *transport_name,
520 GHashTable *key_value_pairs,
521 GCancellable *cancellable,
522 GError **error)
524 GIOStream *ret;
525 GSocketConnectable *connectable;
526 const gchar *nonce_file;
528 connectable = NULL;
529 ret = NULL;
530 nonce_file = NULL;
532 if (FALSE)
535 #ifdef G_OS_UNIX
536 else if (g_strcmp0 (transport_name, "unix") == 0)
538 const gchar *path;
539 const gchar *abstract;
540 path = g_hash_table_lookup (key_value_pairs, "path");
541 abstract = g_hash_table_lookup (key_value_pairs, "abstract");
542 if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
544 g_set_error (error,
545 G_IO_ERROR,
546 G_IO_ERROR_INVALID_ARGUMENT,
547 _("Error in address `%s' - the unix transport requires exactly one of the "
548 "keys `path' or `abstract' to be set"),
549 address_entry);
551 else if (path != NULL)
553 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
555 else if (abstract != NULL)
557 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
559 G_UNIX_SOCKET_ADDRESS_ABSTRACT));
561 else
563 g_assert_not_reached ();
566 #endif
567 else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
569 const gchar *s;
570 const gchar *host;
571 guint port;
572 gchar *endp;
573 gboolean is_nonce;
575 is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
577 host = g_hash_table_lookup (key_value_pairs, "host");
578 if (host == NULL)
580 g_set_error (error,
581 G_IO_ERROR,
582 G_IO_ERROR_INVALID_ARGUMENT,
583 _("Error in address `%s' - the host attribute is missing or malformed"),
584 address_entry);
585 goto out;
588 s = g_hash_table_lookup (key_value_pairs, "port");
589 if (s == NULL)
590 s = "0";
591 port = strtol (s, &endp, 10);
592 if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
594 g_set_error (error,
595 G_IO_ERROR,
596 G_IO_ERROR_INVALID_ARGUMENT,
597 _("Error in address `%s' - the port attribute is missing or malformed"),
598 address_entry);
599 goto out;
603 if (is_nonce)
605 nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
606 if (nonce_file == NULL)
608 g_set_error (error,
609 G_IO_ERROR,
610 G_IO_ERROR_INVALID_ARGUMENT,
611 _("Error in address `%s' - the noncefile attribute is missing or malformed"),
612 address_entry);
613 goto out;
617 /* TODO: deal with family key/value-pair */
618 connectable = g_network_address_new (host, port);
620 else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
622 gchar *autolaunch_address;
623 autolaunch_address = get_session_address_platform_specific (error);
624 if (autolaunch_address != NULL)
626 ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
627 g_free (autolaunch_address);
628 goto out;
630 else
632 g_prefix_error (error, _("Error auto-launching: "));
635 else
637 g_set_error (error,
638 G_IO_ERROR,
639 G_IO_ERROR_INVALID_ARGUMENT,
640 _("Unknown or unsupported transport `%s' for address `%s'"),
641 transport_name,
642 address_entry);
645 if (connectable != NULL)
647 GSocketClient *client;
648 GSocketConnection *connection;
650 g_assert (ret == NULL);
651 client = g_socket_client_new ();
652 connection = g_socket_client_connect (client,
653 connectable,
654 cancellable,
655 error);
656 g_object_unref (connectable);
657 g_object_unref (client);
658 if (connection == NULL)
659 goto out;
661 ret = G_IO_STREAM (connection);
663 if (nonce_file != NULL)
665 gchar nonce_contents[16 + 1];
666 size_t num_bytes_read;
667 FILE *f;
669 /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
670 f = fopen (nonce_file, "rb");
671 if (f == NULL)
673 g_set_error (error,
674 G_IO_ERROR,
675 G_IO_ERROR_INVALID_ARGUMENT,
676 _("Error opening nonce file `%s': %s"),
677 nonce_file,
678 g_strerror (errno));
679 g_object_unref (ret);
680 ret = NULL;
681 goto out;
683 num_bytes_read = fread (nonce_contents,
684 sizeof (gchar),
685 16 + 1,
687 if (num_bytes_read != 16)
689 if (num_bytes_read == 0)
691 g_set_error (error,
692 G_IO_ERROR,
693 G_IO_ERROR_INVALID_ARGUMENT,
694 _("Error reading from nonce file `%s': %s"),
695 nonce_file,
696 g_strerror (errno));
698 else
700 g_set_error (error,
701 G_IO_ERROR,
702 G_IO_ERROR_INVALID_ARGUMENT,
703 _("Error reading from nonce file `%s', expected 16 bytes, got %d"),
704 nonce_file,
705 (gint) num_bytes_read);
707 g_object_unref (ret);
708 ret = NULL;
709 fclose (f);
710 goto out;
712 fclose (f);
714 if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
715 nonce_contents,
717 NULL,
718 cancellable,
719 error))
721 g_prefix_error (error, _("Error writing contents of nonce file `%s' to stream:"), nonce_file);
722 g_object_unref (ret);
723 ret = NULL;
724 goto out;
729 out:
731 return ret;
734 static GIOStream *
735 g_dbus_address_try_connect_one (const gchar *address_entry,
736 gchar **out_guid,
737 GCancellable *cancellable,
738 GError **error)
740 GIOStream *ret;
741 GHashTable *key_value_pairs;
742 gchar *transport_name;
743 const gchar *guid;
745 ret = NULL;
746 transport_name = NULL;
747 key_value_pairs = NULL;
749 if (!_g_dbus_address_parse_entry (address_entry,
750 &transport_name,
751 &key_value_pairs,
752 error))
753 goto out;
755 ret = g_dbus_address_connect (address_entry,
756 transport_name,
757 key_value_pairs,
758 cancellable,
759 error);
760 if (ret == NULL)
761 goto out;
763 guid = g_hash_table_lookup (key_value_pairs, "guid");
764 if (guid != NULL && out_guid != NULL)
765 *out_guid = g_strdup (guid);
767 out:
768 g_free (transport_name);
769 if (key_value_pairs != NULL)
770 g_hash_table_unref (key_value_pairs);
771 return ret;
775 /* ---------------------------------------------------------------------------------------------------- */
777 typedef struct {
778 gchar *address;
779 GIOStream *stream;
780 gchar *guid;
781 } GetStreamData;
783 static void
784 get_stream_data_free (GetStreamData *data)
786 g_free (data->address);
787 if (data->stream != NULL)
788 g_object_unref (data->stream);
789 g_free (data->guid);
790 g_free (data);
793 static void
794 get_stream_thread_func (GSimpleAsyncResult *res,
795 GObject *object,
796 GCancellable *cancellable)
798 GetStreamData *data;
799 GError *error;
801 data = g_simple_async_result_get_op_res_gpointer (res);
803 error = NULL;
804 data->stream = g_dbus_address_get_stream_sync (data->address,
805 &data->guid,
806 cancellable,
807 &error);
808 if (data->stream == NULL)
809 g_simple_async_result_take_error (res, error);
813 * g_dbus_address_get_stream:
814 * @address: A valid D-Bus address.
815 * @cancellable: A #GCancellable or %NULL.
816 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
817 * @user_data: Data to pass to @callback.
819 * Asynchronously connects to an endpoint specified by @address and
820 * sets up the connection so it is in a state to run the client-side
821 * of the D-Bus authentication conversation.
823 * When the operation is finished, @callback will be invoked. You can
824 * then call g_dbus_address_get_stream_finish() to get the result of
825 * the operation.
827 * This is an asynchronous failable function. See
828 * g_dbus_address_get_stream_sync() for the synchronous version.
830 * Since: 2.26
832 void
833 g_dbus_address_get_stream (const gchar *address,
834 GCancellable *cancellable,
835 GAsyncReadyCallback callback,
836 gpointer user_data)
838 GSimpleAsyncResult *res;
839 GetStreamData *data;
841 g_return_if_fail (address != NULL);
843 res = g_simple_async_result_new (NULL,
844 callback,
845 user_data,
846 g_dbus_address_get_stream);
847 data = g_new0 (GetStreamData, 1);
848 data->address = g_strdup (address);
849 g_simple_async_result_set_op_res_gpointer (res,
850 data,
851 (GDestroyNotify) get_stream_data_free);
852 g_simple_async_result_run_in_thread (res,
853 get_stream_thread_func,
854 G_PRIORITY_DEFAULT,
855 cancellable);
856 g_object_unref (res);
860 * g_dbus_address_get_stream_finish:
861 * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
862 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
863 * @error: Return location for error or %NULL.
865 * Finishes an operation started with g_dbus_address_get_stream().
867 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
869 * Since: 2.26
871 GIOStream *
872 g_dbus_address_get_stream_finish (GAsyncResult *res,
873 gchar **out_guid,
874 GError **error)
876 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
877 GetStreamData *data;
878 GIOStream *ret;
880 g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
881 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
883 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
885 ret = NULL;
887 data = g_simple_async_result_get_op_res_gpointer (simple);
888 if (g_simple_async_result_propagate_error (simple, error))
889 goto out;
891 ret = g_object_ref (data->stream);
892 if (out_guid != NULL)
893 *out_guid = g_strdup (data->guid);
895 out:
896 return ret;
900 * g_dbus_address_get_stream_sync:
901 * @address: A valid D-Bus address.
902 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
903 * @cancellable: A #GCancellable or %NULL.
904 * @error: Return location for error or %NULL.
906 * Synchronously connects to an endpoint specified by @address and
907 * sets up the connection so it is in a state to run the client-side
908 * of the D-Bus authentication conversation.
910 * This is a synchronous failable function. See
911 * g_dbus_address_get_stream() for the asynchronous version.
913 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
915 * Since: 2.26
917 GIOStream *
918 g_dbus_address_get_stream_sync (const gchar *address,
919 gchar **out_guid,
920 GCancellable *cancellable,
921 GError **error)
923 GIOStream *ret;
924 gchar **addr_array;
925 guint n;
926 GError *last_error;
928 g_return_val_if_fail (address != NULL, NULL);
929 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
931 ret = NULL;
932 last_error = NULL;
934 addr_array = g_strsplit (address, ";", 0);
935 if (addr_array[0] == NULL)
937 last_error = g_error_new_literal (G_IO_ERROR,
938 G_IO_ERROR_INVALID_ARGUMENT,
939 _("The given address is empty"));
940 goto out;
943 for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
945 const gchar *addr = addr_array[n];
946 GError *this_error;
948 this_error = NULL;
949 ret = g_dbus_address_try_connect_one (addr,
950 out_guid,
951 cancellable,
952 &this_error);
953 if (ret != NULL)
955 goto out;
957 else
959 g_assert (this_error != NULL);
960 if (last_error != NULL)
961 g_error_free (last_error);
962 last_error = this_error;
966 out:
967 if (ret != NULL)
969 if (last_error != NULL)
970 g_error_free (last_error);
972 else
974 g_assert (last_error != NULL);
975 g_propagate_error (error, last_error);
978 g_strfreev (addr_array);
979 return ret;
982 /* ---------------------------------------------------------------------------------------------------- */
984 #ifdef G_OS_UNIX
985 static gchar *
986 get_session_address_dbus_launch (GError **error)
988 gchar *ret;
989 gchar *machine_id;
990 gchar *command_line;
991 gchar *launch_stdout;
992 gchar *launch_stderr;
993 gint exit_status;
994 gchar *old_dbus_verbose;
995 gboolean restore_dbus_verbose;
997 ret = NULL;
998 machine_id = NULL;
999 command_line = NULL;
1000 launch_stdout = NULL;
1001 launch_stderr = NULL;
1002 restore_dbus_verbose = FALSE;
1003 old_dbus_verbose = NULL;
1005 machine_id = _g_dbus_get_machine_id (error);
1006 if (machine_id == NULL)
1008 g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1009 goto out;
1012 /* We're using private libdbus facilities here. When everything
1013 * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1014 * X11 property is correctly documented right now) we should
1015 * consider using the spec instead of dbus-launch.
1017 * --autolaunch=MACHINEID
1018 * This option implies that dbus-launch should scan for a previ‐
1019 * ously-started session and reuse the values found there. If no
1020 * session is found, it will start a new session. The --exit-with-
1021 * session option is implied if --autolaunch is given. This option
1022 * is for the exclusive use of libdbus, you do not want to use it
1023 * manually. It may change in the future.
1026 /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1027 command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1029 if (G_UNLIKELY (_g_dbus_debug_address ()))
1031 _g_dbus_debug_print_lock ();
1032 g_print ("GDBus-debug:Address: Running `%s' to get bus address (possibly autolaunching)\n", command_line);
1033 old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1034 restore_dbus_verbose = TRUE;
1035 g_setenv ("DBUS_VERBOSE", "1", TRUE);
1036 _g_dbus_debug_print_unlock ();
1039 if (!g_spawn_command_line_sync (command_line,
1040 &launch_stdout,
1041 &launch_stderr,
1042 &exit_status,
1043 error))
1045 g_prefix_error (error, _("Error spawning command line `%s': "), command_line);
1046 goto out;
1049 if (!WIFEXITED (exit_status))
1051 gchar *escaped_stderr;
1052 escaped_stderr = g_strescape (launch_stderr, "");
1053 g_set_error (error,
1054 G_IO_ERROR,
1055 G_IO_ERROR_FAILED,
1056 _("Abnormal program termination spawning command line `%s': %s"),
1057 command_line,
1058 escaped_stderr);
1059 g_free (escaped_stderr);
1060 goto out;
1063 if (WEXITSTATUS (exit_status) != 0)
1065 gchar *escaped_stderr;
1066 escaped_stderr = g_strescape (launch_stderr, "");
1067 g_set_error (error,
1068 G_IO_ERROR,
1069 G_IO_ERROR_FAILED,
1070 _("Command line `%s' exited with non-zero exit status %d: %s"),
1071 command_line,
1072 WEXITSTATUS (exit_status),
1073 escaped_stderr);
1074 g_free (escaped_stderr);
1075 goto out;
1078 /* From the dbus-launch(1) man page:
1080 * --binary-syntax Write to stdout a nul-terminated bus address,
1081 * then the bus PID as a binary integer of size sizeof(pid_t),
1082 * then the bus X window ID as a binary integer of size
1083 * sizeof(long). Integers are in the machine's byte order, not
1084 * network byte order or any other canonical byte order.
1086 ret = g_strdup (launch_stdout);
1088 out:
1089 if (G_UNLIKELY (_g_dbus_debug_address ()))
1091 gchar *s;
1092 _g_dbus_debug_print_lock ();
1093 g_print ("GDBus-debug:Address: dbus-launch output:");
1094 if (launch_stdout != NULL)
1096 s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1097 g_print ("\n%s", s);
1098 g_free (s);
1100 else
1102 g_print (" (none)\n");
1104 g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1105 if (launch_stderr != NULL)
1106 g_print ("\n%s", launch_stderr);
1107 else
1108 g_print (" (none)\n");
1109 _g_dbus_debug_print_unlock ();
1112 g_free (machine_id);
1113 g_free (command_line);
1114 g_free (launch_stdout);
1115 g_free (launch_stderr);
1116 if (G_UNLIKELY (restore_dbus_verbose))
1118 if (old_dbus_verbose != NULL)
1119 g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1120 else
1121 g_unsetenv ("DBUS_VERBOSE");
1123 g_free (old_dbus_verbose);
1124 return ret;
1126 #endif
1128 /* ---------------------------------------------------------------------------------------------------- */
1130 static gchar *
1131 get_session_address_platform_specific (GError **error)
1133 gchar *ret;
1134 #ifdef G_OS_UNIX
1135 /* need to handle OS X in a different way since `dbus-launch --autolaunch' probably won't work there */
1136 ret = get_session_address_dbus_launch (error);
1137 #else
1138 /* TODO: implement for UNIX, Win32 and OS X */
1139 ret = NULL;
1140 g_set_error (error,
1141 G_IO_ERROR,
1142 G_IO_ERROR_FAILED,
1143 _("Cannot determine session bus address (not implemented for this OS)"));
1144 #endif
1145 return ret;
1148 /* ---------------------------------------------------------------------------------------------------- */
1151 * g_dbus_address_get_for_bus_sync:
1152 * @bus_type: A #GBusType.
1153 * @cancellable: A #GCancellable or %NULL.
1154 * @error: Return location for error or %NULL.
1156 * Synchronously looks up the D-Bus address for the well-known message
1157 * bus instance specified by @bus_type. This may involve using various
1158 * platform specific mechanisms.
1160 * Returns: A valid D-Bus address string for @bus_type or %NULL if @error is set.
1162 * Since: 2.26
1164 gchar *
1165 g_dbus_address_get_for_bus_sync (GBusType bus_type,
1166 GCancellable *cancellable,
1167 GError **error)
1169 gchar *ret;
1170 const gchar *starter_bus;
1171 GError *local_error;
1173 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1175 ret = NULL;
1176 local_error = NULL;
1178 if (G_UNLIKELY (_g_dbus_debug_address ()))
1180 guint n;
1181 _g_dbus_debug_print_lock ();
1182 g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `%s'\n",
1183 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1184 for (n = 0; n < 3; n++)
1186 const gchar *k;
1187 const gchar *v;
1188 switch (n)
1190 case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1191 case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1192 case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1193 default: g_assert_not_reached ();
1195 v = g_getenv (k);
1196 g_print ("GDBus-debug:Address: env var %s", k);
1197 if (v != NULL)
1198 g_print ("=`%s'\n", v);
1199 else
1200 g_print (" is not set\n");
1202 _g_dbus_debug_print_unlock ();
1205 switch (bus_type)
1207 case G_BUS_TYPE_SYSTEM:
1208 ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1209 if (ret == NULL)
1211 ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1213 break;
1215 case G_BUS_TYPE_SESSION:
1216 ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1217 if (ret == NULL)
1219 ret = get_session_address_platform_specific (&local_error);
1221 break;
1223 case G_BUS_TYPE_STARTER:
1224 starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1225 if (g_strcmp0 (starter_bus, "session") == 0)
1227 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1228 goto out;
1230 else if (g_strcmp0 (starter_bus, "system") == 0)
1232 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1233 goto out;
1235 else
1237 if (starter_bus != NULL)
1239 g_set_error (&local_error,
1240 G_IO_ERROR,
1241 G_IO_ERROR_FAILED,
1242 _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1243 " - unknown value `%s'"),
1244 starter_bus);
1246 else
1248 g_set_error_literal (&local_error,
1249 G_IO_ERROR,
1250 G_IO_ERROR_FAILED,
1251 _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1252 "variable is not set"));
1255 break;
1257 default:
1258 g_set_error (&local_error,
1259 G_IO_ERROR,
1260 G_IO_ERROR_FAILED,
1261 _("Unknown bus type %d"),
1262 bus_type);
1263 break;
1266 out:
1267 if (G_UNLIKELY (_g_dbus_debug_address ()))
1269 _g_dbus_debug_print_lock ();
1270 if (ret != NULL)
1272 g_print ("GDBus-debug:Address: Returning address `%s' for bus type `%s'\n",
1273 ret,
1274 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1276 else
1278 g_print ("GDBus-debug:Address: Cannot look-up address bus type `%s': %s\n",
1279 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
1280 local_error->message);
1282 _g_dbus_debug_print_unlock ();
1285 if (local_error != NULL)
1286 g_propagate_error (error, local_error);
1288 return ret;