It is 'registered', not 'registred'
[glib.git] / gio / gdbusaddress.c
blobfac22b713bcdf324ac5fa1baa1a2da1fd39d95a1
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"
41 #include "giomodule-priv.h"
42 #include "gdbusdaemon.h"
44 #ifdef G_OS_UNIX
45 #include <gio/gunixsocketaddress.h>
46 #endif
48 #ifdef G_OS_WIN32
49 #include <windows.h>
50 #include <io.h>
51 #include <conio.h>
52 #endif
54 #include "glibintl.h"
56 /**
57 * SECTION:gdbusaddress
58 * @title: D-Bus Addresses
59 * @short_description: D-Bus connection endpoints
60 * @include: gio/gio.h
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 <link linkend="http://dbus.freedesktop.org/doc/dbus-specification.html&num;addresses">D-Bus specification</link>.
67 static gchar *get_session_address_platform_specific (GError **error);
69 /* ---------------------------------------------------------------------------------------------------- */
71 /**
72 * g_dbus_is_address:
73 * @string: A string.
75 * Checks if @string is a D-Bus address.
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.
81 * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
83 * Since: 2.26
85 gboolean
86 g_dbus_is_address (const gchar *string)
88 guint n;
89 gchar **a;
90 gboolean ret;
92 ret = FALSE;
94 g_return_val_if_fail (string != NULL, FALSE);
96 a = g_strsplit (string, ";", 0);
97 if (a[0] == NULL)
98 goto out;
100 for (n = 0; a[n] != NULL; n++)
102 if (!_g_dbus_address_parse_entry (a[n],
103 NULL,
104 NULL,
105 NULL))
106 goto out;
109 ret = TRUE;
111 out:
112 g_strfreev (a);
113 return ret;
116 static gboolean
117 is_valid_unix (const gchar *address_entry,
118 GHashTable *key_value_pairs,
119 GError **error)
121 gboolean ret;
122 GList *keys;
123 GList *l;
124 const gchar *path;
125 const gchar *tmpdir;
126 const gchar *abstract;
128 ret = FALSE;
129 keys = NULL;
130 path = NULL;
131 tmpdir = NULL;
132 abstract = NULL;
134 keys = g_hash_table_get_keys (key_value_pairs);
135 for (l = keys; l != NULL; l = l->next)
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
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;
156 if (path != NULL)
158 if (tmpdir != NULL || abstract != NULL)
159 goto meaningless;
161 else if (tmpdir != NULL)
163 if (path != NULL || abstract != NULL)
164 goto meaningless;
166 else if (abstract != NULL)
168 if (path != NULL || tmpdir != NULL)
169 goto meaningless;
171 else
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;
182 ret= TRUE;
183 goto out;
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);
192 out:
193 g_list_free (keys);
195 return ret;
198 static gboolean
199 is_valid_nonce_tcp (const gchar *address_entry,
200 GHashTable *key_value_pairs,
201 GError **error)
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;
213 ret = FALSE;
214 keys = NULL;
215 host = NULL;
216 port = NULL;
217 family = NULL;
218 nonce_file = NULL;
220 keys = g_hash_table_get_keys (key_value_pairs);
221 for (l = keys; l != NULL; l = l->next)
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
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;
244 if (port != NULL)
246 port_num = strtol (port, &endp, 10);
247 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
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;
258 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
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;
268 if (host != NULL)
270 /* TODO: validate host */
273 nonce_file = nonce_file; /* To avoid -Wunused-but-set-variable */
275 ret= TRUE;
277 out:
278 g_list_free (keys);
280 return ret;
283 static gboolean
284 is_valid_tcp (const gchar *address_entry,
285 GHashTable *key_value_pairs,
286 GError **error)
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;
297 ret = FALSE;
298 keys = NULL;
299 host = NULL;
300 port = NULL;
301 family = NULL;
303 keys = g_hash_table_get_keys (key_value_pairs);
304 for (l = keys; l != NULL; l = l->next)
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
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;
325 if (port != NULL)
327 port_num = strtol (port, &endp, 10);
328 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
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;
339 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
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;
349 if (host != NULL)
351 /* TODO: validate host */
354 ret= TRUE;
356 out:
357 g_list_free (keys);
359 return ret;
363 * g_dbus_is_supported_address:
364 * @string: A string.
365 * @error: Return location for error or %NULL.
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.
371 * Returns: %TRUE if @string is a valid D-Bus address that is
372 * supported by this library, %FALSE if @error is set.
374 * Since: 2.26
376 gboolean
377 g_dbus_is_supported_address (const gchar *string,
378 GError **error)
380 guint n;
381 gchar **a;
382 gboolean ret;
384 ret = FALSE;
386 g_return_val_if_fail (string != NULL, FALSE);
387 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
389 a = g_strsplit (string, ";", 0);
390 for (n = 0; a[n] != NULL; n++)
392 gchar *transport_name;
393 GHashTable *key_value_pairs;
394 gboolean supported;
396 if (!_g_dbus_address_parse_entry (a[n],
397 &transport_name,
398 &key_value_pairs,
399 error))
400 goto out;
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;
412 g_free (transport_name);
413 g_hash_table_unref (key_value_pairs);
415 if (!supported)
416 goto out;
419 ret = TRUE;
421 out:
422 g_strfreev (a);
424 g_assert (ret || (!ret && (error == NULL || *error != NULL)));
426 return ret;
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)
435 gboolean ret;
436 GHashTable *key_value_pairs;
437 gchar *transport_name;
438 gchar **kv_pairs;
439 const gchar *s;
440 guint n;
442 ret = FALSE;
443 kv_pairs = NULL;
444 transport_name = NULL;
445 key_value_pairs = NULL;
447 s = strchr (address_entry, ':');
448 if (s == NULL)
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;
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);
461 kv_pairs = g_strsplit (s + 1, ",", 0);
462 for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
464 const gchar *kv_pair = kv_pairs[n];
465 gchar *key;
466 gchar *value;
468 s = strchr (kv_pair, '=');
469 if (s == NULL)
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"),
476 kv_pair,
477 address_entry);
478 goto out;
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)
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'"),
490 kv_pair,
491 address_entry);
492 g_free (key);
493 g_free (value);
494 goto out;
496 g_hash_table_insert (key_value_pairs, key, value);
499 ret = TRUE;
501 out:
502 g_strfreev (kv_pairs);
503 if (ret)
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);
514 else
516 g_free (transport_name);
517 if (key_value_pairs != NULL)
518 g_hash_table_unref (key_value_pairs);
520 return ret;
523 /* ---------------------------------------------------------------------------------------------------- */
525 static GIOStream *
526 g_dbus_address_try_connect_one (const gchar *address_entry,
527 gchar **out_guid,
528 GCancellable *cancellable,
529 GError **error);
531 /* TODO: Declare an extension point called GDBusTransport (or similar)
532 * and move code below to extensions implementing said extension
533 * point. That way we can implement a D-Bus transport over X11 without
534 * making libgio link to libX11...
536 static GIOStream *
537 g_dbus_address_connect (const gchar *address_entry,
538 const gchar *transport_name,
539 GHashTable *key_value_pairs,
540 GCancellable *cancellable,
541 GError **error)
543 GIOStream *ret;
544 GSocketConnectable *connectable;
545 const gchar *nonce_file;
547 connectable = NULL;
548 ret = NULL;
549 nonce_file = NULL;
551 if (FALSE)
554 #ifdef G_OS_UNIX
555 else if (g_strcmp0 (transport_name, "unix") == 0)
557 const gchar *path;
558 const gchar *abstract;
559 path = g_hash_table_lookup (key_value_pairs, "path");
560 abstract = g_hash_table_lookup (key_value_pairs, "abstract");
561 if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
563 g_set_error (error,
564 G_IO_ERROR,
565 G_IO_ERROR_INVALID_ARGUMENT,
566 _("Error in address `%s' - the unix transport requires exactly one of the "
567 "keys `path' or `abstract' to be set"),
568 address_entry);
570 else if (path != NULL)
572 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
574 else if (abstract != NULL)
576 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
578 G_UNIX_SOCKET_ADDRESS_ABSTRACT));
580 else
582 g_assert_not_reached ();
585 #endif
586 else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
588 const gchar *s;
589 const gchar *host;
590 glong port;
591 gchar *endp;
592 gboolean is_nonce;
594 is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
596 host = g_hash_table_lookup (key_value_pairs, "host");
597 if (host == NULL)
599 g_set_error (error,
600 G_IO_ERROR,
601 G_IO_ERROR_INVALID_ARGUMENT,
602 _("Error in address `%s' - the host attribute is missing or malformed"),
603 address_entry);
604 goto out;
607 s = g_hash_table_lookup (key_value_pairs, "port");
608 if (s == NULL)
609 s = "0";
610 port = strtol (s, &endp, 10);
611 if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
613 g_set_error (error,
614 G_IO_ERROR,
615 G_IO_ERROR_INVALID_ARGUMENT,
616 _("Error in address `%s' - the port attribute is missing or malformed"),
617 address_entry);
618 goto out;
622 if (is_nonce)
624 nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
625 if (nonce_file == NULL)
627 g_set_error (error,
628 G_IO_ERROR,
629 G_IO_ERROR_INVALID_ARGUMENT,
630 _("Error in address `%s' - the noncefile attribute is missing or malformed"),
631 address_entry);
632 goto out;
636 /* TODO: deal with family key/value-pair */
637 connectable = g_network_address_new (host, port);
639 else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
641 gchar *autolaunch_address;
642 autolaunch_address = get_session_address_platform_specific (error);
643 if (autolaunch_address != NULL)
645 ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
646 g_free (autolaunch_address);
647 goto out;
649 else
651 g_prefix_error (error, _("Error auto-launching: "));
654 else
656 g_set_error (error,
657 G_IO_ERROR,
658 G_IO_ERROR_INVALID_ARGUMENT,
659 _("Unknown or unsupported transport `%s' for address `%s'"),
660 transport_name,
661 address_entry);
664 if (connectable != NULL)
666 GSocketClient *client;
667 GSocketConnection *connection;
669 g_assert (ret == NULL);
670 client = g_socket_client_new ();
671 connection = g_socket_client_connect (client,
672 connectable,
673 cancellable,
674 error);
675 g_object_unref (connectable);
676 g_object_unref (client);
677 if (connection == NULL)
678 goto out;
680 ret = G_IO_STREAM (connection);
682 if (nonce_file != NULL)
684 gchar nonce_contents[16 + 1];
685 size_t num_bytes_read;
686 FILE *f;
688 /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
689 f = fopen (nonce_file, "rb");
690 if (f == NULL)
692 g_set_error (error,
693 G_IO_ERROR,
694 G_IO_ERROR_INVALID_ARGUMENT,
695 _("Error opening nonce file `%s': %s"),
696 nonce_file,
697 g_strerror (errno));
698 g_object_unref (ret);
699 ret = NULL;
700 goto out;
702 num_bytes_read = fread (nonce_contents,
703 sizeof (gchar),
704 16 + 1,
706 if (num_bytes_read != 16)
708 if (num_bytes_read == 0)
710 g_set_error (error,
711 G_IO_ERROR,
712 G_IO_ERROR_INVALID_ARGUMENT,
713 _("Error reading from nonce file `%s': %s"),
714 nonce_file,
715 g_strerror (errno));
717 else
719 g_set_error (error,
720 G_IO_ERROR,
721 G_IO_ERROR_INVALID_ARGUMENT,
722 _("Error reading from nonce file `%s', expected 16 bytes, got %d"),
723 nonce_file,
724 (gint) num_bytes_read);
726 g_object_unref (ret);
727 ret = NULL;
728 fclose (f);
729 goto out;
731 fclose (f);
733 if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
734 nonce_contents,
736 NULL,
737 cancellable,
738 error))
740 g_prefix_error (error, _("Error writing contents of nonce file `%s' to stream:"), nonce_file);
741 g_object_unref (ret);
742 ret = NULL;
743 goto out;
748 out:
750 return ret;
753 static GIOStream *
754 g_dbus_address_try_connect_one (const gchar *address_entry,
755 gchar **out_guid,
756 GCancellable *cancellable,
757 GError **error)
759 GIOStream *ret;
760 GHashTable *key_value_pairs;
761 gchar *transport_name;
762 const gchar *guid;
764 ret = NULL;
765 transport_name = NULL;
766 key_value_pairs = NULL;
768 if (!_g_dbus_address_parse_entry (address_entry,
769 &transport_name,
770 &key_value_pairs,
771 error))
772 goto out;
774 ret = g_dbus_address_connect (address_entry,
775 transport_name,
776 key_value_pairs,
777 cancellable,
778 error);
779 if (ret == NULL)
780 goto out;
782 guid = g_hash_table_lookup (key_value_pairs, "guid");
783 if (guid != NULL && out_guid != NULL)
784 *out_guid = g_strdup (guid);
786 out:
787 g_free (transport_name);
788 if (key_value_pairs != NULL)
789 g_hash_table_unref (key_value_pairs);
790 return ret;
794 /* ---------------------------------------------------------------------------------------------------- */
796 typedef struct {
797 gchar *address;
798 GIOStream *stream;
799 gchar *guid;
800 } GetStreamData;
802 static void
803 get_stream_data_free (GetStreamData *data)
805 g_free (data->address);
806 if (data->stream != NULL)
807 g_object_unref (data->stream);
808 g_free (data->guid);
809 g_free (data);
812 static void
813 get_stream_thread_func (GSimpleAsyncResult *res,
814 GObject *object,
815 GCancellable *cancellable)
817 GetStreamData *data;
818 GError *error;
820 data = g_simple_async_result_get_op_res_gpointer (res);
822 error = NULL;
823 data->stream = g_dbus_address_get_stream_sync (data->address,
824 &data->guid,
825 cancellable,
826 &error);
827 if (data->stream == NULL)
828 g_simple_async_result_take_error (res, error);
832 * g_dbus_address_get_stream:
833 * @address: A valid D-Bus address.
834 * @cancellable: (allow-none): A #GCancellable or %NULL.
835 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
836 * @user_data: Data to pass to @callback.
838 * Asynchronously connects to an endpoint specified by @address and
839 * sets up the connection so it is in a state to run the client-side
840 * of the D-Bus authentication conversation.
842 * When the operation is finished, @callback will be invoked. You can
843 * then call g_dbus_address_get_stream_finish() to get the result of
844 * the operation.
846 * This is an asynchronous failable function. See
847 * g_dbus_address_get_stream_sync() for the synchronous version.
849 * Since: 2.26
851 void
852 g_dbus_address_get_stream (const gchar *address,
853 GCancellable *cancellable,
854 GAsyncReadyCallback callback,
855 gpointer user_data)
857 GSimpleAsyncResult *res;
858 GetStreamData *data;
860 g_return_if_fail (address != NULL);
862 res = g_simple_async_result_new (NULL,
863 callback,
864 user_data,
865 g_dbus_address_get_stream);
866 g_simple_async_result_set_check_cancellable (res, cancellable);
867 data = g_new0 (GetStreamData, 1);
868 data->address = g_strdup (address);
869 g_simple_async_result_set_op_res_gpointer (res,
870 data,
871 (GDestroyNotify) get_stream_data_free);
872 g_simple_async_result_run_in_thread (res,
873 get_stream_thread_func,
874 G_PRIORITY_DEFAULT,
875 cancellable);
876 g_object_unref (res);
880 * g_dbus_address_get_stream_finish:
881 * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
882 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
883 * @error: Return location for error or %NULL.
885 * Finishes an operation started with g_dbus_address_get_stream().
887 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
889 * Since: 2.26
891 GIOStream *
892 g_dbus_address_get_stream_finish (GAsyncResult *res,
893 gchar **out_guid,
894 GError **error)
896 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
897 GetStreamData *data;
898 GIOStream *ret;
900 g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
901 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
903 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
905 ret = NULL;
907 data = g_simple_async_result_get_op_res_gpointer (simple);
908 if (g_simple_async_result_propagate_error (simple, error))
909 goto out;
911 ret = g_object_ref (data->stream);
912 if (out_guid != NULL)
913 *out_guid = g_strdup (data->guid);
915 out:
916 return ret;
920 * g_dbus_address_get_stream_sync:
921 * @address: A valid D-Bus address.
922 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
923 * @cancellable: (allow-none): A #GCancellable or %NULL.
924 * @error: Return location for error or %NULL.
926 * Synchronously connects to an endpoint specified by @address and
927 * sets up the connection so it is in a state to run the client-side
928 * of the D-Bus authentication conversation.
930 * This is a synchronous failable function. See
931 * g_dbus_address_get_stream() for the asynchronous version.
933 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
935 * Since: 2.26
937 GIOStream *
938 g_dbus_address_get_stream_sync (const gchar *address,
939 gchar **out_guid,
940 GCancellable *cancellable,
941 GError **error)
943 GIOStream *ret;
944 gchar **addr_array;
945 guint n;
946 GError *last_error;
948 g_return_val_if_fail (address != NULL, NULL);
949 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
951 ret = NULL;
952 last_error = NULL;
954 addr_array = g_strsplit (address, ";", 0);
955 if (addr_array != NULL && addr_array[0] == NULL)
957 last_error = g_error_new_literal (G_IO_ERROR,
958 G_IO_ERROR_INVALID_ARGUMENT,
959 _("The given address is empty"));
960 goto out;
963 for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
965 const gchar *addr = addr_array[n];
966 GError *this_error;
968 this_error = NULL;
969 ret = g_dbus_address_try_connect_one (addr,
970 out_guid,
971 cancellable,
972 &this_error);
973 if (ret != NULL)
975 goto out;
977 else
979 g_assert (this_error != NULL);
980 if (last_error != NULL)
981 g_error_free (last_error);
982 last_error = this_error;
986 out:
987 if (ret != NULL)
989 if (last_error != NULL)
990 g_error_free (last_error);
992 else
994 g_assert (last_error != NULL);
995 g_propagate_error (error, last_error);
998 g_strfreev (addr_array);
999 return ret;
1002 /* ---------------------------------------------------------------------------------------------------- */
1004 #ifdef G_OS_UNIX
1005 static gchar *
1006 get_session_address_dbus_launch (GError **error)
1008 gchar *ret;
1009 gchar *machine_id;
1010 gchar *command_line;
1011 gchar *launch_stdout;
1012 gchar *launch_stderr;
1013 gint exit_status;
1014 gchar *old_dbus_verbose;
1015 gboolean restore_dbus_verbose;
1017 ret = NULL;
1018 machine_id = NULL;
1019 command_line = NULL;
1020 launch_stdout = NULL;
1021 launch_stderr = NULL;
1022 restore_dbus_verbose = FALSE;
1023 old_dbus_verbose = NULL;
1025 machine_id = _g_dbus_get_machine_id (error);
1026 if (machine_id == NULL)
1028 g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1029 goto out;
1032 /* We're using private libdbus facilities here. When everything
1033 * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1034 * X11 property is correctly documented right now) we should
1035 * consider using the spec instead of dbus-launch.
1037 * --autolaunch=MACHINEID
1038 * This option implies that dbus-launch should scan for a previ‐
1039 * ously-started session and reuse the values found there. If no
1040 * session is found, it will start a new session. The --exit-with-
1041 * session option is implied if --autolaunch is given. This option
1042 * is for the exclusive use of libdbus, you do not want to use it
1043 * manually. It may change in the future.
1046 /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1047 command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1049 if (G_UNLIKELY (_g_dbus_debug_address ()))
1051 _g_dbus_debug_print_lock ();
1052 g_print ("GDBus-debug:Address: Running `%s' to get bus address (possibly autolaunching)\n", command_line);
1053 old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1054 restore_dbus_verbose = TRUE;
1055 g_setenv ("DBUS_VERBOSE", "1", TRUE);
1056 _g_dbus_debug_print_unlock ();
1059 if (!g_spawn_command_line_sync (command_line,
1060 &launch_stdout,
1061 &launch_stderr,
1062 &exit_status,
1063 error))
1065 goto out;
1068 if (!g_spawn_check_exit_status (exit_status, error))
1070 g_prefix_error (error, _("Error spawning command line `%s': "), command_line);
1071 goto out;
1074 /* From the dbus-launch(1) man page:
1076 * --binary-syntax Write to stdout a nul-terminated bus address,
1077 * then the bus PID as a binary integer of size sizeof(pid_t),
1078 * then the bus X window ID as a binary integer of size
1079 * sizeof(long). Integers are in the machine's byte order, not
1080 * network byte order or any other canonical byte order.
1082 ret = g_strdup (launch_stdout);
1084 out:
1085 if (G_UNLIKELY (_g_dbus_debug_address ()))
1087 gchar *s;
1088 _g_dbus_debug_print_lock ();
1089 g_print ("GDBus-debug:Address: dbus-launch output:");
1090 if (launch_stdout != NULL)
1092 s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1093 g_print ("\n%s", s);
1094 g_free (s);
1096 else
1098 g_print (" (none)\n");
1100 g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1101 if (launch_stderr != NULL)
1102 g_print ("\n%s", launch_stderr);
1103 else
1104 g_print (" (none)\n");
1105 _g_dbus_debug_print_unlock ();
1108 g_free (machine_id);
1109 g_free (command_line);
1110 g_free (launch_stdout);
1111 g_free (launch_stderr);
1112 if (G_UNLIKELY (restore_dbus_verbose))
1114 if (old_dbus_verbose != NULL)
1115 g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1116 else
1117 g_unsetenv ("DBUS_VERBOSE");
1119 g_free (old_dbus_verbose);
1120 return ret;
1122 #endif
1124 #ifdef G_OS_WIN32
1126 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1127 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1128 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1129 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1131 static void
1132 release_mutex (HANDLE mutex)
1134 ReleaseMutex (mutex);
1135 CloseHandle (mutex);
1138 static HANDLE
1139 acquire_mutex (const char *mutexname)
1141 HANDLE mutex;
1142 DWORD res;
1144 mutex = CreateMutexA (NULL, FALSE, mutexname);
1145 if (!mutex)
1146 return 0;
1148 res = WaitForSingleObject (mutex, INFINITE);
1149 switch (res)
1151 case WAIT_ABANDONED:
1152 release_mutex (mutex);
1153 return 0;
1154 case WAIT_FAILED:
1155 case WAIT_TIMEOUT:
1156 return 0;
1159 return mutex;
1162 static gboolean
1163 is_mutex_owned (const char *mutexname)
1165 HANDLE mutex;
1166 gboolean res = FALSE;
1168 mutex = CreateMutexA (NULL, FALSE, mutexname);
1169 if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1170 res = TRUE;
1171 else
1172 ReleaseMutex (mutex);
1173 CloseHandle (mutex);
1175 return res;
1178 static char *
1179 read_shm (const char *shm_name)
1181 HANDLE shared_mem;
1182 char *shared_data;
1183 char *res;
1184 int i;
1186 res = NULL;
1188 for (i = 0; i < 20; i++)
1190 shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1191 if (shared_mem != 0)
1192 break;
1193 Sleep (100);
1196 if (shared_mem != 0)
1198 shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1199 if (shared_data != NULL)
1201 res = g_strdup (shared_data);
1202 UnmapViewOfFile (shared_data);
1204 CloseHandle (shared_mem);
1207 return res;
1210 static HANDLE
1211 set_shm (const char *shm_name, const char *value)
1213 HANDLE shared_mem;
1214 char *shared_data;
1216 shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1217 0, strlen (value) + 1, shm_name);
1218 if (shared_mem == 0)
1219 return 0;
1221 shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1222 if (shared_data == NULL)
1223 return 0;
1225 strcpy (shared_data, value);
1227 UnmapViewOfFile (shared_data);
1229 return shared_mem;
1232 /* These keep state between publish_session_bus and unpublish_session_bus */
1233 static HANDLE published_daemon_mutex;
1234 static HANDLE published_shared_mem;
1236 static gboolean
1237 publish_session_bus (const char *address)
1239 HANDLE init_mutex;
1241 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1243 published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1244 if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1246 release_mutex (init_mutex);
1247 CloseHandle (published_daemon_mutex);
1248 published_daemon_mutex = NULL;
1249 return FALSE;
1252 published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1253 if (!published_shared_mem)
1255 release_mutex (init_mutex);
1256 CloseHandle (published_daemon_mutex);
1257 published_daemon_mutex = NULL;
1258 return FALSE;
1261 release_mutex (init_mutex);
1262 return TRUE;
1265 static void
1266 unpublish_session_bus ()
1268 HANDLE init_mutex;
1270 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1272 CloseHandle (published_shared_mem);
1273 published_shared_mem = NULL;
1275 release_mutex (published_daemon_mutex);
1276 published_daemon_mutex = NULL;
1278 release_mutex (init_mutex);
1281 static void
1282 wait_console_window (void)
1284 FILE *console = fopen ("CONOUT$", "w");
1286 SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1287 fprintf (console, _("(Type any character to close this window)\n"));
1288 fflush (console);
1289 _getch ();
1292 static void
1293 open_console_window (void)
1295 if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1296 (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1298 if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1299 freopen ("CONOUT$", "w", stdout);
1301 if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1302 freopen ("CONOUT$", "w", stderr);
1304 SetConsoleTitleW (L"gdbus-daemon debug output.");
1306 atexit (wait_console_window);
1309 static void
1310 idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1312 GMainLoop *loop = user_data;
1313 g_main_loop_quit (loop);
1316 __declspec(dllexport) void CALLBACK
1317 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1319 GDBusDaemon *daemon;
1320 GMainLoop *loop;
1321 const char *address;
1322 GError *error = NULL;
1324 if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1325 open_console_window ();
1327 g_type_init ();
1329 loop = g_main_loop_new (NULL, FALSE);
1331 address = "nonce-tcp:";
1332 daemon = _g_dbus_daemon_new (address, NULL, &error);
1333 if (daemon == NULL)
1335 g_printerr ("Can't init bus: %s\n", error->message);
1336 return;
1339 g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1341 if ( publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1343 g_main_loop_run (loop);
1345 unpublish_session_bus ();
1348 g_main_loop_unref (loop);
1349 g_object_unref (daemon);
1352 static gchar *
1353 get_session_address_dbus_launch (GError **error)
1355 HANDLE autolaunch_mutex, init_mutex;
1356 char *address = NULL;
1357 wchar_t gio_path[MAX_PATH+1+200];
1359 autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1361 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1363 if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1364 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1366 release_mutex (init_mutex);
1368 if (address == NULL)
1370 gio_path[MAX_PATH] = 0;
1371 if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1373 PROCESS_INFORMATION pi = { 0 };
1374 STARTUPINFOW si = { 0 };
1375 BOOL res;
1376 wchar_t gio_path_short[MAX_PATH];
1377 wchar_t rundll_path[MAX_PATH*2];
1378 wchar_t args[MAX_PATH*4];
1380 GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1382 GetWindowsDirectoryW (rundll_path, MAX_PATH);
1383 wcscat (rundll_path, L"\\rundll32.exe");
1384 if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1386 GetSystemDirectoryW (rundll_path, MAX_PATH);
1387 wcscat (rundll_path, L"\\rundll32.exe");
1390 wcscpy (args, L"\"");
1391 wcscat (args, rundll_path);
1392 wcscat (args, L"\" ");
1393 wcscat (args, gio_path_short);
1394 wcscat (args, L",g_win32_run_session_bus@16");
1396 res = CreateProcessW (rundll_path, args,
1397 0, 0, FALSE,
1398 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1399 0, NULL /* TODO: Should be root */,
1400 &si, &pi);
1401 if (res)
1402 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1406 release_mutex (autolaunch_mutex);
1408 if (address == NULL)
1409 g_set_error (error,
1410 G_IO_ERROR,
1411 G_IO_ERROR_FAILED,
1412 _("Session dbus not running, and autolaunch failed"));
1414 return address;
1416 #endif
1418 /* ---------------------------------------------------------------------------------------------------- */
1420 static gchar *
1421 get_session_address_platform_specific (GError **error)
1423 gchar *ret;
1424 #if defined (G_OS_UNIX) || defined(G_OS_WIN32)
1425 /* need to handle OS X in a different way since `dbus-launch --autolaunch' probably won't work there */
1426 ret = get_session_address_dbus_launch (error);
1427 #else
1428 /* TODO: implement for OS X */
1429 ret = NULL;
1430 g_set_error (error,
1431 G_IO_ERROR,
1432 G_IO_ERROR_FAILED,
1433 _("Cannot determine session bus address (not implemented for this OS)"));
1434 #endif
1435 return ret;
1438 /* ---------------------------------------------------------------------------------------------------- */
1441 * g_dbus_address_get_for_bus_sync:
1442 * @bus_type: A #GBusType.
1443 * @cancellable: (allow-none): A #GCancellable or %NULL.
1444 * @error: Return location for error or %NULL.
1446 * Synchronously looks up the D-Bus address for the well-known message
1447 * bus instance specified by @bus_type. This may involve using various
1448 * platform specific mechanisms.
1450 * Returns: A valid D-Bus address string for @bus_type or %NULL if @error is set.
1452 * Since: 2.26
1454 gchar *
1455 g_dbus_address_get_for_bus_sync (GBusType bus_type,
1456 GCancellable *cancellable,
1457 GError **error)
1459 gchar *ret;
1460 const gchar *starter_bus;
1461 GError *local_error;
1463 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1465 ret = NULL;
1466 local_error = NULL;
1468 if (G_UNLIKELY (_g_dbus_debug_address ()))
1470 guint n;
1471 _g_dbus_debug_print_lock ();
1472 g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type `%s'\n",
1473 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1474 for (n = 0; n < 3; n++)
1476 const gchar *k;
1477 const gchar *v;
1478 switch (n)
1480 case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1481 case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1482 case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1483 default: g_assert_not_reached ();
1485 v = g_getenv (k);
1486 g_print ("GDBus-debug:Address: env var %s", k);
1487 if (v != NULL)
1488 g_print ("=`%s'\n", v);
1489 else
1490 g_print (" is not set\n");
1492 _g_dbus_debug_print_unlock ();
1495 switch (bus_type)
1497 case G_BUS_TYPE_SYSTEM:
1498 ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1499 if (ret == NULL)
1501 ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1503 break;
1505 case G_BUS_TYPE_SESSION:
1506 ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1507 if (ret == NULL)
1509 ret = get_session_address_platform_specific (&local_error);
1511 break;
1513 case G_BUS_TYPE_STARTER:
1514 starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1515 if (g_strcmp0 (starter_bus, "session") == 0)
1517 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1518 goto out;
1520 else if (g_strcmp0 (starter_bus, "system") == 0)
1522 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1523 goto out;
1525 else
1527 if (starter_bus != NULL)
1529 g_set_error (&local_error,
1530 G_IO_ERROR,
1531 G_IO_ERROR_FAILED,
1532 _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1533 " - unknown value `%s'"),
1534 starter_bus);
1536 else
1538 g_set_error_literal (&local_error,
1539 G_IO_ERROR,
1540 G_IO_ERROR_FAILED,
1541 _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1542 "variable is not set"));
1545 break;
1547 default:
1548 g_set_error (&local_error,
1549 G_IO_ERROR,
1550 G_IO_ERROR_FAILED,
1551 _("Unknown bus type %d"),
1552 bus_type);
1553 break;
1556 out:
1557 if (G_UNLIKELY (_g_dbus_debug_address ()))
1559 _g_dbus_debug_print_lock ();
1560 if (ret != NULL)
1562 g_print ("GDBus-debug:Address: Returning address `%s' for bus type `%s'\n",
1563 ret,
1564 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1566 else
1568 g_print ("GDBus-debug:Address: Cannot look-up address bus type `%s': %s\n",
1569 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
1570 local_error ? local_error->message : "");
1572 _g_dbus_debug_print_unlock ();
1575 if (local_error != NULL)
1576 g_propagate_error (error, local_error);
1578 return ret;