tests: only chmod autorun.exe on UNIX
[glib.git] / gio / gdbusaddress.c
blob6d17b7c813d01cf2eb84952af2640b51748e40e6
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, see <http://www.gnu.org/licenses/>.
18 * Author: David Zeuthen <davidz@redhat.com>
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
28 #include "gioerror.h"
29 #include "gdbusutils.h"
30 #include "gdbusaddress.h"
31 #include "gdbuserror.h"
32 #include "gioenumtypes.h"
33 #include "gnetworkaddress.h"
34 #include "gsocketclient.h"
35 #include "giostream.h"
36 #include "gasyncresult.h"
37 #include "gsimpleasyncresult.h"
38 #include "glib-private.h"
39 #include "gdbusprivate.h"
40 #include "giomodule-priv.h"
41 #include "gdbusdaemon.h"
43 #ifdef G_OS_UNIX
44 #include <gio/gunixsocketaddress.h>
45 #endif
47 #ifdef G_OS_WIN32
48 #include <windows.h>
49 #include <io.h>
50 #include <conio.h>
51 #endif
53 #include "glibintl.h"
55 /**
56 * SECTION:gdbusaddress
57 * @title: D-Bus Addresses
58 * @short_description: D-Bus connection endpoints
59 * @include: gio/gio.h
61 * Routines for working with D-Bus addresses. A D-Bus address is a string
62 * like "unix:tmpdir=/tmp/my-app-name". The exact format of addresses
63 * is explained in detail in the [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html\#addresses).
66 static gchar *get_session_address_platform_specific (GError **error);
68 /* ---------------------------------------------------------------------------------------------------- */
70 /**
71 * g_dbus_is_address:
72 * @string: A string.
74 * Checks if @string is a D-Bus address.
76 * This doesn't check if @string is actually supported by #GDBusServer
77 * or #GDBusConnection - use g_dbus_is_supported_address() to do more
78 * checks.
80 * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
82 * Since: 2.26
84 gboolean
85 g_dbus_is_address (const gchar *string)
87 guint n;
88 gchar **a;
89 gboolean ret;
91 ret = FALSE;
93 g_return_val_if_fail (string != NULL, FALSE);
95 a = g_strsplit (string, ";", 0);
96 if (a[0] == NULL)
97 goto out;
99 for (n = 0; a[n] != NULL; n++)
101 if (!_g_dbus_address_parse_entry (a[n],
102 NULL,
103 NULL,
104 NULL))
105 goto out;
108 ret = TRUE;
110 out:
111 g_strfreev (a);
112 return ret;
115 static gboolean
116 is_valid_unix (const gchar *address_entry,
117 GHashTable *key_value_pairs,
118 GError **error)
120 gboolean ret;
121 GList *keys;
122 GList *l;
123 const gchar *path;
124 const gchar *tmpdir;
125 const gchar *abstract;
127 ret = FALSE;
128 keys = NULL;
129 path = NULL;
130 tmpdir = NULL;
131 abstract = NULL;
133 keys = g_hash_table_get_keys (key_value_pairs);
134 for (l = keys; l != NULL; l = l->next)
136 const gchar *key = l->data;
137 if (g_strcmp0 (key, "path") == 0)
138 path = g_hash_table_lookup (key_value_pairs, key);
139 else if (g_strcmp0 (key, "tmpdir") == 0)
140 tmpdir = g_hash_table_lookup (key_value_pairs, key);
141 else if (g_strcmp0 (key, "abstract") == 0)
142 abstract = g_hash_table_lookup (key_value_pairs, key);
143 else
145 g_set_error (error,
146 G_IO_ERROR,
147 G_IO_ERROR_INVALID_ARGUMENT,
148 _("Unsupported key '%s' in address entry '%s'"),
149 key,
150 address_entry);
151 goto out;
155 if (path != NULL)
157 if (tmpdir != NULL || abstract != NULL)
158 goto meaningless;
160 else if (tmpdir != NULL)
162 if (path != NULL || abstract != NULL)
163 goto meaningless;
165 else if (abstract != NULL)
167 if (path != NULL || tmpdir != NULL)
168 goto meaningless;
170 else
172 g_set_error (error,
173 G_IO_ERROR,
174 G_IO_ERROR_INVALID_ARGUMENT,
175 _("Address '%s' is invalid (need exactly one of path, tmpdir or abstract keys)"),
176 address_entry);
177 goto out;
181 ret= TRUE;
182 goto out;
184 meaningless:
185 g_set_error (error,
186 G_IO_ERROR,
187 G_IO_ERROR_INVALID_ARGUMENT,
188 _("Meaningless key/value pair combination in address entry '%s'"),
189 address_entry);
191 out:
192 g_list_free (keys);
194 return ret;
197 static gboolean
198 is_valid_nonce_tcp (const gchar *address_entry,
199 GHashTable *key_value_pairs,
200 GError **error)
202 gboolean ret;
203 GList *keys;
204 GList *l;
205 const gchar *host;
206 const gchar *port;
207 const gchar *family;
208 const gchar *nonce_file;
209 gint port_num;
210 gchar *endp;
212 ret = FALSE;
213 keys = NULL;
214 host = NULL;
215 port = NULL;
216 family = NULL;
217 nonce_file = NULL;
219 keys = g_hash_table_get_keys (key_value_pairs);
220 for (l = keys; l != NULL; l = l->next)
222 const gchar *key = l->data;
223 if (g_strcmp0 (key, "host") == 0)
224 host = g_hash_table_lookup (key_value_pairs, key);
225 else if (g_strcmp0 (key, "port") == 0)
226 port = g_hash_table_lookup (key_value_pairs, key);
227 else if (g_strcmp0 (key, "family") == 0)
228 family = g_hash_table_lookup (key_value_pairs, key);
229 else if (g_strcmp0 (key, "noncefile") == 0)
230 nonce_file = g_hash_table_lookup (key_value_pairs, key);
231 else
233 g_set_error (error,
234 G_IO_ERROR,
235 G_IO_ERROR_INVALID_ARGUMENT,
236 _("Unsupported key '%s' in address entry '%s'"),
237 key,
238 address_entry);
239 goto out;
243 if (port != NULL)
245 port_num = strtol (port, &endp, 10);
246 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
248 g_set_error (error,
249 G_IO_ERROR,
250 G_IO_ERROR_INVALID_ARGUMENT,
251 _("Error in address '%s' - the port attribute is malformed"),
252 address_entry);
253 goto out;
257 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
259 g_set_error (error,
260 G_IO_ERROR,
261 G_IO_ERROR_INVALID_ARGUMENT,
262 _("Error in address '%s' - the family attribute is malformed"),
263 address_entry);
264 goto out;
267 if (host != NULL)
269 /* TODO: validate host */
272 nonce_file = nonce_file; /* To avoid -Wunused-but-set-variable */
274 ret= TRUE;
276 out:
277 g_list_free (keys);
279 return ret;
282 static gboolean
283 is_valid_tcp (const gchar *address_entry,
284 GHashTable *key_value_pairs,
285 GError **error)
287 gboolean ret;
288 GList *keys;
289 GList *l;
290 const gchar *host;
291 const gchar *port;
292 const gchar *family;
293 gint port_num;
294 gchar *endp;
296 ret = FALSE;
297 keys = NULL;
298 host = NULL;
299 port = NULL;
300 family = NULL;
302 keys = g_hash_table_get_keys (key_value_pairs);
303 for (l = keys; l != NULL; l = l->next)
305 const gchar *key = l->data;
306 if (g_strcmp0 (key, "host") == 0)
307 host = g_hash_table_lookup (key_value_pairs, key);
308 else if (g_strcmp0 (key, "port") == 0)
309 port = g_hash_table_lookup (key_value_pairs, key);
310 else if (g_strcmp0 (key, "family") == 0)
311 family = g_hash_table_lookup (key_value_pairs, key);
312 else
314 g_set_error (error,
315 G_IO_ERROR,
316 G_IO_ERROR_INVALID_ARGUMENT,
317 _("Unsupported key '%s' in address entry '%s'"),
318 key,
319 address_entry);
320 goto out;
324 if (port != NULL)
326 port_num = strtol (port, &endp, 10);
327 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
329 g_set_error (error,
330 G_IO_ERROR,
331 G_IO_ERROR_INVALID_ARGUMENT,
332 _("Error in address '%s' - the port attribute is malformed"),
333 address_entry);
334 goto out;
338 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
340 g_set_error (error,
341 G_IO_ERROR,
342 G_IO_ERROR_INVALID_ARGUMENT,
343 _("Error in address '%s' - the family attribute is malformed"),
344 address_entry);
345 goto out;
348 if (host != NULL)
350 /* TODO: validate host */
353 ret= TRUE;
355 out:
356 g_list_free (keys);
358 return ret;
362 * g_dbus_is_supported_address:
363 * @string: A string.
364 * @error: Return location for error or %NULL.
366 * Like g_dbus_is_address() but also checks if the library suppors the
367 * transports in @string and that key/value pairs for each transport
368 * are valid.
370 * Returns: %TRUE if @string is a valid D-Bus address that is
371 * supported by this library, %FALSE if @error is set.
373 * Since: 2.26
375 gboolean
376 g_dbus_is_supported_address (const gchar *string,
377 GError **error)
379 guint n;
380 gchar **a;
381 gboolean ret;
383 ret = FALSE;
385 g_return_val_if_fail (string != NULL, FALSE);
386 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
388 a = g_strsplit (string, ";", 0);
389 for (n = 0; a[n] != NULL; n++)
391 gchar *transport_name;
392 GHashTable *key_value_pairs;
393 gboolean supported;
395 if (!_g_dbus_address_parse_entry (a[n],
396 &transport_name,
397 &key_value_pairs,
398 error))
399 goto out;
401 supported = FALSE;
402 if (g_strcmp0 (transport_name, "unix") == 0)
403 supported = is_valid_unix (a[n], key_value_pairs, error);
404 else if (g_strcmp0 (transport_name, "tcp") == 0)
405 supported = is_valid_tcp (a[n], key_value_pairs, error);
406 else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
407 supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
408 else if (g_strcmp0 (a[n], "autolaunch:") == 0)
409 supported = TRUE;
411 g_free (transport_name);
412 g_hash_table_unref (key_value_pairs);
414 if (!supported)
415 goto out;
418 ret = TRUE;
420 out:
421 g_strfreev (a);
423 g_assert (ret || (!ret && (error == NULL || *error != NULL)));
425 return ret;
428 gboolean
429 _g_dbus_address_parse_entry (const gchar *address_entry,
430 gchar **out_transport_name,
431 GHashTable **out_key_value_pairs,
432 GError **error)
434 gboolean ret;
435 GHashTable *key_value_pairs;
436 gchar *transport_name;
437 gchar **kv_pairs;
438 const gchar *s;
439 guint n;
441 ret = FALSE;
442 kv_pairs = NULL;
443 transport_name = NULL;
444 key_value_pairs = NULL;
446 s = strchr (address_entry, ':');
447 if (s == NULL)
449 g_set_error (error,
450 G_IO_ERROR,
451 G_IO_ERROR_INVALID_ARGUMENT,
452 _("Address element '%s' does not contain a colon (:)"),
453 address_entry);
454 goto out;
457 transport_name = g_strndup (address_entry, s - address_entry);
458 key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
460 kv_pairs = g_strsplit (s + 1, ",", 0);
461 for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
463 const gchar *kv_pair = kv_pairs[n];
464 gchar *key;
465 gchar *value;
467 s = strchr (kv_pair, '=');
468 if (s == NULL)
470 g_set_error (error,
471 G_IO_ERROR,
472 G_IO_ERROR_INVALID_ARGUMENT,
473 _("Key/Value pair %d, '%s', in address element '%s' does not contain an equal sign"),
475 kv_pair,
476 address_entry);
477 goto out;
480 key = g_uri_unescape_segment (kv_pair, s, NULL);
481 value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
482 if (key == NULL || value == NULL)
484 g_set_error (error,
485 G_IO_ERROR,
486 G_IO_ERROR_INVALID_ARGUMENT,
487 _("Error unescaping key or value in Key/Value pair %d, '%s', in address element '%s'"),
489 kv_pair,
490 address_entry);
491 g_free (key);
492 g_free (value);
493 goto out;
495 g_hash_table_insert (key_value_pairs, key, value);
498 ret = TRUE;
500 out:
501 g_strfreev (kv_pairs);
502 if (ret)
504 if (out_transport_name != NULL)
505 *out_transport_name = transport_name;
506 else
507 g_free (transport_name);
508 if (out_key_value_pairs != NULL)
509 *out_key_value_pairs = key_value_pairs;
510 else if (key_value_pairs != NULL)
511 g_hash_table_unref (key_value_pairs);
513 else
515 g_free (transport_name);
516 if (key_value_pairs != NULL)
517 g_hash_table_unref (key_value_pairs);
519 return ret;
522 /* ---------------------------------------------------------------------------------------------------- */
524 static GIOStream *
525 g_dbus_address_try_connect_one (const gchar *address_entry,
526 gchar **out_guid,
527 GCancellable *cancellable,
528 GError **error);
530 /* TODO: Declare an extension point called GDBusTransport (or similar)
531 * and move code below to extensions implementing said extension
532 * point. That way we can implement a D-Bus transport over X11 without
533 * making libgio link to libX11...
535 static GIOStream *
536 g_dbus_address_connect (const gchar *address_entry,
537 const gchar *transport_name,
538 GHashTable *key_value_pairs,
539 GCancellable *cancellable,
540 GError **error)
542 GIOStream *ret;
543 GSocketConnectable *connectable;
544 const gchar *nonce_file;
546 connectable = NULL;
547 ret = NULL;
548 nonce_file = NULL;
550 if (FALSE)
553 #ifdef G_OS_UNIX
554 else if (g_strcmp0 (transport_name, "unix") == 0)
556 const gchar *path;
557 const gchar *abstract;
558 path = g_hash_table_lookup (key_value_pairs, "path");
559 abstract = g_hash_table_lookup (key_value_pairs, "abstract");
560 if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
562 g_set_error (error,
563 G_IO_ERROR,
564 G_IO_ERROR_INVALID_ARGUMENT,
565 _("Error in address '%s' - the unix transport requires exactly one of the "
566 "keys 'path' or 'abstract' to be set"),
567 address_entry);
569 else if (path != NULL)
571 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
573 else if (abstract != NULL)
575 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
577 G_UNIX_SOCKET_ADDRESS_ABSTRACT));
579 else
581 g_assert_not_reached ();
584 #endif
585 else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
587 const gchar *s;
588 const gchar *host;
589 glong port;
590 gchar *endp;
591 gboolean is_nonce;
593 is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
595 host = g_hash_table_lookup (key_value_pairs, "host");
596 if (host == NULL)
598 g_set_error (error,
599 G_IO_ERROR,
600 G_IO_ERROR_INVALID_ARGUMENT,
601 _("Error in address '%s' - the host attribute is missing or malformed"),
602 address_entry);
603 goto out;
606 s = g_hash_table_lookup (key_value_pairs, "port");
607 if (s == NULL)
608 s = "0";
609 port = strtol (s, &endp, 10);
610 if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
612 g_set_error (error,
613 G_IO_ERROR,
614 G_IO_ERROR_INVALID_ARGUMENT,
615 _("Error in address '%s' - the port attribute is missing or malformed"),
616 address_entry);
617 goto out;
621 if (is_nonce)
623 nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
624 if (nonce_file == NULL)
626 g_set_error (error,
627 G_IO_ERROR,
628 G_IO_ERROR_INVALID_ARGUMENT,
629 _("Error in address '%s' - the noncefile attribute is missing or malformed"),
630 address_entry);
631 goto out;
635 /* TODO: deal with family key/value-pair */
636 connectable = g_network_address_new (host, port);
638 else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
640 gchar *autolaunch_address;
641 autolaunch_address = get_session_address_platform_specific (error);
642 if (autolaunch_address != NULL)
644 ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
645 g_free (autolaunch_address);
646 goto out;
648 else
650 g_prefix_error (error, _("Error auto-launching: "));
653 else
655 g_set_error (error,
656 G_IO_ERROR,
657 G_IO_ERROR_INVALID_ARGUMENT,
658 _("Unknown or unsupported transport '%s' for address '%s'"),
659 transport_name,
660 address_entry);
663 if (connectable != NULL)
665 GSocketClient *client;
666 GSocketConnection *connection;
668 g_assert (ret == NULL);
669 client = g_socket_client_new ();
670 connection = g_socket_client_connect (client,
671 connectable,
672 cancellable,
673 error);
674 g_object_unref (connectable);
675 g_object_unref (client);
676 if (connection == NULL)
677 goto out;
679 ret = G_IO_STREAM (connection);
681 if (nonce_file != NULL)
683 gchar nonce_contents[16 + 1];
684 size_t num_bytes_read;
685 FILE *f;
687 /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
688 f = fopen (nonce_file, "rb");
689 if (f == NULL)
691 g_set_error (error,
692 G_IO_ERROR,
693 G_IO_ERROR_INVALID_ARGUMENT,
694 _("Error opening nonce file '%s': %s"),
695 nonce_file,
696 g_strerror (errno));
697 g_object_unref (ret);
698 ret = NULL;
699 goto out;
701 num_bytes_read = fread (nonce_contents,
702 sizeof (gchar),
703 16 + 1,
705 if (num_bytes_read != 16)
707 if (num_bytes_read == 0)
709 g_set_error (error,
710 G_IO_ERROR,
711 G_IO_ERROR_INVALID_ARGUMENT,
712 _("Error reading from nonce file '%s': %s"),
713 nonce_file,
714 g_strerror (errno));
716 else
718 g_set_error (error,
719 G_IO_ERROR,
720 G_IO_ERROR_INVALID_ARGUMENT,
721 _("Error reading from nonce file '%s', expected 16 bytes, got %d"),
722 nonce_file,
723 (gint) num_bytes_read);
725 g_object_unref (ret);
726 ret = NULL;
727 fclose (f);
728 goto out;
730 fclose (f);
732 if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
733 nonce_contents,
735 NULL,
736 cancellable,
737 error))
739 g_prefix_error (error, _("Error writing contents of nonce file '%s' to stream:"), nonce_file);
740 g_object_unref (ret);
741 ret = NULL;
742 goto out;
747 out:
749 return ret;
752 static GIOStream *
753 g_dbus_address_try_connect_one (const gchar *address_entry,
754 gchar **out_guid,
755 GCancellable *cancellable,
756 GError **error)
758 GIOStream *ret;
759 GHashTable *key_value_pairs;
760 gchar *transport_name;
761 const gchar *guid;
763 ret = NULL;
764 transport_name = NULL;
765 key_value_pairs = NULL;
767 if (!_g_dbus_address_parse_entry (address_entry,
768 &transport_name,
769 &key_value_pairs,
770 error))
771 goto out;
773 ret = g_dbus_address_connect (address_entry,
774 transport_name,
775 key_value_pairs,
776 cancellable,
777 error);
778 if (ret == NULL)
779 goto out;
781 guid = g_hash_table_lookup (key_value_pairs, "guid");
782 if (guid != NULL && out_guid != NULL)
783 *out_guid = g_strdup (guid);
785 out:
786 g_free (transport_name);
787 if (key_value_pairs != NULL)
788 g_hash_table_unref (key_value_pairs);
789 return ret;
793 /* ---------------------------------------------------------------------------------------------------- */
795 typedef struct {
796 gchar *address;
797 GIOStream *stream;
798 gchar *guid;
799 } GetStreamData;
801 static void
802 get_stream_data_free (GetStreamData *data)
804 g_free (data->address);
805 if (data->stream != NULL)
806 g_object_unref (data->stream);
807 g_free (data->guid);
808 g_free (data);
811 static void
812 get_stream_thread_func (GSimpleAsyncResult *res,
813 GObject *object,
814 GCancellable *cancellable)
816 GetStreamData *data;
817 GError *error;
819 data = g_simple_async_result_get_op_res_gpointer (res);
821 error = NULL;
822 data->stream = g_dbus_address_get_stream_sync (data->address,
823 &data->guid,
824 cancellable,
825 &error);
826 if (data->stream == NULL)
827 g_simple_async_result_take_error (res, error);
831 * g_dbus_address_get_stream:
832 * @address: A valid D-Bus address.
833 * @cancellable: (allow-none): A #GCancellable or %NULL.
834 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
835 * @user_data: Data to pass to @callback.
837 * Asynchronously connects to an endpoint specified by @address and
838 * sets up the connection so it is in a state to run the client-side
839 * of the D-Bus authentication conversation.
841 * When the operation is finished, @callback will be invoked. You can
842 * then call g_dbus_address_get_stream_finish() to get the result of
843 * the operation.
845 * This is an asynchronous failable function. See
846 * g_dbus_address_get_stream_sync() for the synchronous version.
848 * Since: 2.26
850 void
851 g_dbus_address_get_stream (const gchar *address,
852 GCancellable *cancellable,
853 GAsyncReadyCallback callback,
854 gpointer user_data)
856 GSimpleAsyncResult *res;
857 GetStreamData *data;
859 g_return_if_fail (address != NULL);
861 res = g_simple_async_result_new (NULL,
862 callback,
863 user_data,
864 g_dbus_address_get_stream);
865 g_simple_async_result_set_check_cancellable (res, cancellable);
866 data = g_new0 (GetStreamData, 1);
867 data->address = g_strdup (address);
868 g_simple_async_result_set_op_res_gpointer (res,
869 data,
870 (GDestroyNotify) get_stream_data_free);
871 g_simple_async_result_run_in_thread (res,
872 get_stream_thread_func,
873 G_PRIORITY_DEFAULT,
874 cancellable);
875 g_object_unref (res);
879 * g_dbus_address_get_stream_finish:
880 * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
881 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
882 * @error: Return location for error or %NULL.
884 * Finishes an operation started with g_dbus_address_get_stream().
886 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
888 * Since: 2.26
890 GIOStream *
891 g_dbus_address_get_stream_finish (GAsyncResult *res,
892 gchar **out_guid,
893 GError **error)
895 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
896 GetStreamData *data;
897 GIOStream *ret;
899 g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
900 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
902 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
904 ret = NULL;
906 data = g_simple_async_result_get_op_res_gpointer (simple);
907 if (g_simple_async_result_propagate_error (simple, error))
908 goto out;
910 ret = g_object_ref (data->stream);
911 if (out_guid != NULL)
912 *out_guid = g_strdup (data->guid);
914 out:
915 return ret;
919 * g_dbus_address_get_stream_sync:
920 * @address: A valid D-Bus address.
921 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
922 * @cancellable: (allow-none): A #GCancellable or %NULL.
923 * @error: Return location for error or %NULL.
925 * Synchronously connects to an endpoint specified by @address and
926 * sets up the connection so it is in a state to run the client-side
927 * of the D-Bus authentication conversation.
929 * This is a synchronous failable function. See
930 * g_dbus_address_get_stream() for the asynchronous version.
932 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
934 * Since: 2.26
936 GIOStream *
937 g_dbus_address_get_stream_sync (const gchar *address,
938 gchar **out_guid,
939 GCancellable *cancellable,
940 GError **error)
942 GIOStream *ret;
943 gchar **addr_array;
944 guint n;
945 GError *last_error;
947 g_return_val_if_fail (address != NULL, NULL);
948 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
950 ret = NULL;
951 last_error = NULL;
953 addr_array = g_strsplit (address, ";", 0);
954 if (addr_array != NULL && addr_array[0] == NULL)
956 last_error = g_error_new_literal (G_IO_ERROR,
957 G_IO_ERROR_INVALID_ARGUMENT,
958 _("The given address is empty"));
959 goto out;
962 for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
964 const gchar *addr = addr_array[n];
965 GError *this_error;
967 this_error = NULL;
968 ret = g_dbus_address_try_connect_one (addr,
969 out_guid,
970 cancellable,
971 &this_error);
972 if (ret != NULL)
974 goto out;
976 else
978 g_assert (this_error != NULL);
979 if (last_error != NULL)
980 g_error_free (last_error);
981 last_error = this_error;
985 out:
986 if (ret != NULL)
988 if (last_error != NULL)
989 g_error_free (last_error);
991 else
993 g_assert (last_error != NULL);
994 g_propagate_error (error, last_error);
997 g_strfreev (addr_array);
998 return ret;
1001 /* ---------------------------------------------------------------------------------------------------- */
1003 #ifdef G_OS_UNIX
1004 static gchar *
1005 get_session_address_dbus_launch (GError **error)
1007 gchar *ret;
1008 gchar *machine_id;
1009 gchar *command_line;
1010 gchar *launch_stdout;
1011 gchar *launch_stderr;
1012 gint exit_status;
1013 gchar *old_dbus_verbose;
1014 gboolean restore_dbus_verbose;
1016 ret = NULL;
1017 machine_id = NULL;
1018 command_line = NULL;
1019 launch_stdout = NULL;
1020 launch_stderr = NULL;
1021 restore_dbus_verbose = FALSE;
1022 old_dbus_verbose = NULL;
1024 /* Don't run binaries as root if we're setuid. */
1025 if (GLIB_PRIVATE_CALL (g_check_setuid) ())
1027 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1028 _("Cannot spawn a message bus when setuid"));
1029 goto out;
1032 machine_id = _g_dbus_get_machine_id (error);
1033 if (machine_id == NULL)
1035 g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1036 goto out;
1039 /* We're using private libdbus facilities here. When everything
1040 * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1041 * X11 property is correctly documented right now) we should
1042 * consider using the spec instead of dbus-launch.
1044 * --autolaunch=MACHINEID
1045 * This option implies that dbus-launch should scan for a previ‐
1046 * ously-started session and reuse the values found there. If no
1047 * session is found, it will start a new session. The --exit-with-
1048 * session option is implied if --autolaunch is given. This option
1049 * is for the exclusive use of libdbus, you do not want to use it
1050 * manually. It may change in the future.
1053 /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1054 command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1056 if (G_UNLIKELY (_g_dbus_debug_address ()))
1058 _g_dbus_debug_print_lock ();
1059 g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
1060 old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1061 restore_dbus_verbose = TRUE;
1062 g_setenv ("DBUS_VERBOSE", "1", TRUE);
1063 _g_dbus_debug_print_unlock ();
1066 if (!g_spawn_command_line_sync (command_line,
1067 &launch_stdout,
1068 &launch_stderr,
1069 &exit_status,
1070 error))
1072 goto out;
1075 if (!g_spawn_check_exit_status (exit_status, error))
1077 g_prefix_error (error, _("Error spawning command line '%s': "), command_line);
1078 goto out;
1081 /* From the dbus-launch(1) man page:
1083 * --binary-syntax Write to stdout a nul-terminated bus address,
1084 * then the bus PID as a binary integer of size sizeof(pid_t),
1085 * then the bus X window ID as a binary integer of size
1086 * sizeof(long). Integers are in the machine's byte order, not
1087 * network byte order or any other canonical byte order.
1089 ret = g_strdup (launch_stdout);
1091 out:
1092 if (G_UNLIKELY (_g_dbus_debug_address ()))
1094 gchar *s;
1095 _g_dbus_debug_print_lock ();
1096 g_print ("GDBus-debug:Address: dbus-launch output:");
1097 if (launch_stdout != NULL)
1099 s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1100 g_print ("\n%s", s);
1101 g_free (s);
1103 else
1105 g_print (" (none)\n");
1107 g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1108 if (launch_stderr != NULL)
1109 g_print ("\n%s", launch_stderr);
1110 else
1111 g_print (" (none)\n");
1112 _g_dbus_debug_print_unlock ();
1115 g_free (machine_id);
1116 g_free (command_line);
1117 g_free (launch_stdout);
1118 g_free (launch_stderr);
1119 if (G_UNLIKELY (restore_dbus_verbose))
1121 if (old_dbus_verbose != NULL)
1122 g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1123 else
1124 g_unsetenv ("DBUS_VERBOSE");
1126 g_free (old_dbus_verbose);
1127 return ret;
1129 #endif
1131 #ifdef G_OS_WIN32
1133 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1134 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1135 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1136 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1138 static void
1139 release_mutex (HANDLE mutex)
1141 ReleaseMutex (mutex);
1142 CloseHandle (mutex);
1145 static HANDLE
1146 acquire_mutex (const char *mutexname)
1148 HANDLE mutex;
1149 DWORD res;
1151 mutex = CreateMutexA (NULL, FALSE, mutexname);
1152 if (!mutex)
1153 return 0;
1155 res = WaitForSingleObject (mutex, INFINITE);
1156 switch (res)
1158 case WAIT_ABANDONED:
1159 release_mutex (mutex);
1160 return 0;
1161 case WAIT_FAILED:
1162 case WAIT_TIMEOUT:
1163 return 0;
1166 return mutex;
1169 static gboolean
1170 is_mutex_owned (const char *mutexname)
1172 HANDLE mutex;
1173 gboolean res = FALSE;
1175 mutex = CreateMutexA (NULL, FALSE, mutexname);
1176 if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1177 res = TRUE;
1178 else
1179 ReleaseMutex (mutex);
1180 CloseHandle (mutex);
1182 return res;
1185 static char *
1186 read_shm (const char *shm_name)
1188 HANDLE shared_mem;
1189 char *shared_data;
1190 char *res;
1191 int i;
1193 res = NULL;
1195 for (i = 0; i < 20; i++)
1197 shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1198 if (shared_mem != 0)
1199 break;
1200 Sleep (100);
1203 if (shared_mem != 0)
1205 shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1206 if (shared_data != NULL)
1208 res = g_strdup (shared_data);
1209 UnmapViewOfFile (shared_data);
1211 CloseHandle (shared_mem);
1214 return res;
1217 static HANDLE
1218 set_shm (const char *shm_name, const char *value)
1220 HANDLE shared_mem;
1221 char *shared_data;
1223 shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1224 0, strlen (value) + 1, shm_name);
1225 if (shared_mem == 0)
1226 return 0;
1228 shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1229 if (shared_data == NULL)
1230 return 0;
1232 strcpy (shared_data, value);
1234 UnmapViewOfFile (shared_data);
1236 return shared_mem;
1239 /* These keep state between publish_session_bus and unpublish_session_bus */
1240 static HANDLE published_daemon_mutex;
1241 static HANDLE published_shared_mem;
1243 static gboolean
1244 publish_session_bus (const char *address)
1246 HANDLE init_mutex;
1248 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1250 published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1251 if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1253 release_mutex (init_mutex);
1254 CloseHandle (published_daemon_mutex);
1255 published_daemon_mutex = NULL;
1256 return FALSE;
1259 published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1260 if (!published_shared_mem)
1262 release_mutex (init_mutex);
1263 CloseHandle (published_daemon_mutex);
1264 published_daemon_mutex = NULL;
1265 return FALSE;
1268 release_mutex (init_mutex);
1269 return TRUE;
1272 static void
1273 unpublish_session_bus (void)
1275 HANDLE init_mutex;
1277 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1279 CloseHandle (published_shared_mem);
1280 published_shared_mem = NULL;
1282 release_mutex (published_daemon_mutex);
1283 published_daemon_mutex = NULL;
1285 release_mutex (init_mutex);
1288 static void
1289 wait_console_window (void)
1291 FILE *console = fopen ("CONOUT$", "w");
1293 SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1294 fprintf (console, _("(Type any character to close this window)\n"));
1295 fflush (console);
1296 _getch ();
1299 static void
1300 open_console_window (void)
1302 if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1303 (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1305 if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1306 freopen ("CONOUT$", "w", stdout);
1308 if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1309 freopen ("CONOUT$", "w", stderr);
1311 SetConsoleTitleW (L"gdbus-daemon debug output.");
1313 atexit (wait_console_window);
1316 static void
1317 idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1319 GMainLoop *loop = user_data;
1320 g_main_loop_quit (loop);
1323 __declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
1325 __declspec(dllexport) void CALLBACK
1326 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1328 GDBusDaemon *daemon;
1329 GMainLoop *loop;
1330 const char *address;
1331 GError *error = NULL;
1333 if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1334 open_console_window ();
1336 loop = g_main_loop_new (NULL, FALSE);
1338 address = "nonce-tcp:";
1339 daemon = _g_dbus_daemon_new (address, NULL, &error);
1340 if (daemon == NULL)
1342 g_printerr ("Can't init bus: %s\n", error->message);
1343 return;
1346 g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1348 if ( publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1350 g_main_loop_run (loop);
1352 unpublish_session_bus ();
1355 g_main_loop_unref (loop);
1356 g_object_unref (daemon);
1359 static gchar *
1360 get_session_address_dbus_launch (GError **error)
1362 HANDLE autolaunch_mutex, init_mutex;
1363 char *address = NULL;
1364 wchar_t gio_path[MAX_PATH+1+200];
1366 autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1368 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1370 if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1371 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1373 release_mutex (init_mutex);
1375 if (address == NULL)
1377 gio_path[MAX_PATH] = 0;
1378 if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1380 PROCESS_INFORMATION pi = { 0 };
1381 STARTUPINFOW si = { 0 };
1382 BOOL res;
1383 wchar_t gio_path_short[MAX_PATH];
1384 wchar_t rundll_path[MAX_PATH*2];
1385 wchar_t args[MAX_PATH*4];
1387 GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1389 GetWindowsDirectoryW (rundll_path, MAX_PATH);
1390 wcscat (rundll_path, L"\\rundll32.exe");
1391 if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1393 GetSystemDirectoryW (rundll_path, MAX_PATH);
1394 wcscat (rundll_path, L"\\rundll32.exe");
1397 wcscpy (args, L"\"");
1398 wcscat (args, rundll_path);
1399 wcscat (args, L"\" ");
1400 wcscat (args, gio_path_short);
1401 #if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
1402 wcscat (args, L",g_win32_run_session_bus");
1403 #elif defined (_MSC_VER)
1404 wcscat (args, L",_g_win32_run_session_bus@16");
1405 #else
1406 wcscat (args, L",g_win32_run_session_bus@16");
1407 #endif
1409 res = CreateProcessW (rundll_path, args,
1410 0, 0, FALSE,
1411 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1412 0, NULL /* TODO: Should be root */,
1413 &si, &pi);
1414 if (res)
1415 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1419 release_mutex (autolaunch_mutex);
1421 if (address == NULL)
1422 g_set_error (error,
1423 G_IO_ERROR,
1424 G_IO_ERROR_FAILED,
1425 _("Session dbus not running, and autolaunch failed"));
1427 return address;
1429 #endif
1431 /* ---------------------------------------------------------------------------------------------------- */
1433 static gchar *
1434 get_session_address_platform_specific (GError **error)
1436 gchar *ret;
1437 #if defined (G_OS_UNIX) || defined(G_OS_WIN32)
1438 /* need to handle OS X in a different way since 'dbus-launch --autolaunch' probably won't work there */
1439 ret = get_session_address_dbus_launch (error);
1440 #else
1441 /* TODO: implement for OS X */
1442 ret = NULL;
1443 g_set_error (error,
1444 G_IO_ERROR,
1445 G_IO_ERROR_FAILED,
1446 _("Cannot determine session bus address (not implemented for this OS)"));
1447 #endif
1448 return ret;
1451 /* ---------------------------------------------------------------------------------------------------- */
1454 * g_dbus_address_get_for_bus_sync:
1455 * @bus_type: a #GBusType
1456 * @cancellable: (allow-none): a #GCancellable or %NULL
1457 * @error: return location for error or %NULL
1459 * Synchronously looks up the D-Bus address for the well-known message
1460 * bus instance specified by @bus_type. This may involve using various
1461 * platform specific mechanisms.
1463 * Returns: a valid D-Bus address string for @bus_type or %NULL if
1464 * @error is set
1466 * Since: 2.26
1468 gchar *
1469 g_dbus_address_get_for_bus_sync (GBusType bus_type,
1470 GCancellable *cancellable,
1471 GError **error)
1473 gchar *ret;
1474 const gchar *starter_bus;
1475 GError *local_error;
1477 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1479 ret = NULL;
1480 local_error = NULL;
1482 if (G_UNLIKELY (_g_dbus_debug_address ()))
1484 guint n;
1485 _g_dbus_debug_print_lock ();
1486 g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1487 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1488 for (n = 0; n < 3; n++)
1490 const gchar *k;
1491 const gchar *v;
1492 switch (n)
1494 case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1495 case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1496 case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1497 default: g_assert_not_reached ();
1499 v = g_getenv (k);
1500 g_print ("GDBus-debug:Address: env var %s", k);
1501 if (v != NULL)
1502 g_print ("='%s'\n", v);
1503 else
1504 g_print (" is not set\n");
1506 _g_dbus_debug_print_unlock ();
1509 switch (bus_type)
1511 case G_BUS_TYPE_SYSTEM:
1512 ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1513 if (ret == NULL)
1515 ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1517 break;
1519 case G_BUS_TYPE_SESSION:
1520 ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1521 if (ret == NULL)
1523 ret = get_session_address_platform_specific (&local_error);
1525 break;
1527 case G_BUS_TYPE_STARTER:
1528 starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1529 if (g_strcmp0 (starter_bus, "session") == 0)
1531 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1532 goto out;
1534 else if (g_strcmp0 (starter_bus, "system") == 0)
1536 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1537 goto out;
1539 else
1541 if (starter_bus != NULL)
1543 g_set_error (&local_error,
1544 G_IO_ERROR,
1545 G_IO_ERROR_FAILED,
1546 _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1547 " - unknown value '%s'"),
1548 starter_bus);
1550 else
1552 g_set_error_literal (&local_error,
1553 G_IO_ERROR,
1554 G_IO_ERROR_FAILED,
1555 _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1556 "variable is not set"));
1559 break;
1561 default:
1562 g_set_error (&local_error,
1563 G_IO_ERROR,
1564 G_IO_ERROR_FAILED,
1565 _("Unknown bus type %d"),
1566 bus_type);
1567 break;
1570 out:
1571 if (G_UNLIKELY (_g_dbus_debug_address ()))
1573 _g_dbus_debug_print_lock ();
1574 if (ret != NULL)
1576 g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1577 ret,
1578 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1580 else
1582 g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1583 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
1584 local_error ? local_error->message : "");
1586 _g_dbus_debug_print_unlock ();
1589 if (local_error != NULL)
1590 g_propagate_error (error, local_error);
1592 return ret;
1596 * g_dbus_address_escape_value:
1597 * @string: an unescaped string to be included in a D-Bus address
1598 * as the value in a key-value pair
1600 * Escape @string so it can appear in a D-Bus address as the value
1601 * part of a key-value pair.
1603 * For instance, if @string is "/run/bus-for-:0",
1604 * this function would return "/run/bus-for-%3A0",
1605 * which could be used in a D-Bus address like
1606 * "unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0".
1608 * Returns: (transfer full): a copy of @string with all
1609 * non-optionally-escaped bytes escaped
1611 * Since: 2.36
1613 gchar *
1614 g_dbus_address_escape_value (const gchar *string)
1616 GString *s;
1617 gsize i;
1619 g_return_val_if_fail (string != NULL, NULL);
1621 /* There will often not be anything needing escaping at all. */
1622 s = g_string_sized_new (strlen (string));
1624 /* D-Bus address escaping is mostly the same as URI escaping... */
1625 g_string_append_uri_escaped (s, string, "\\/", FALSE);
1627 /* ... but '~' is an unreserved character in URIs, but a
1628 * non-optionally-escaped character in D-Bus addresses. */
1629 for (i = 0; i < s->len; i++)
1631 if (G_UNLIKELY (s->str[i] == '~'))
1633 s->str[i] = '%';
1634 g_string_insert (s, i + 1, "7E");
1635 i += 2;
1639 return g_string_free (s, FALSE);