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>
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"
45 #include <gio/gunixsocketaddress.h>
57 * SECTION:gdbusaddress
58 * @title: D-Bus Addresses
59 * @short_description: D-Bus connection endpoints
62 * Routines for working with D-Bus addresses. A D-Bus address is a string
63 * like "unix:tmpdir=/tmp/my-app-name". The exact format of addresses
64 * is explained in detail in the [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html\#addresses).
67 static gchar *get_session_address_platform_specific (GError **error);
69 /* ---------------------------------------------------------------------------------------------------- */
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
81 * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
86 g_dbus_is_address (const gchar *string)
94 g_return_val_if_fail (string != NULL, FALSE);
96 a = g_strsplit (string, ";", 0);
100 for (n = 0; a[n] != NULL; n++)
102 if (!_g_dbus_address_parse_entry (a[n],
117 is_valid_unix (const gchar *address_entry,
118 GHashTable *key_value_pairs,
126 const gchar *abstract;
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);
148 G_IO_ERROR_INVALID_ARGUMENT,
149 _("Unsupported key '%s' in address entry '%s'"),
158 if (tmpdir != NULL || abstract != NULL)
161 else if (tmpdir != NULL)
163 if (path != NULL || abstract != NULL)
166 else if (abstract != NULL)
168 if (path != NULL || tmpdir != NULL)
175 G_IO_ERROR_INVALID_ARGUMENT,
176 _("Address '%s' is invalid (need exactly one of path, tmpdir or abstract keys)"),
188 G_IO_ERROR_INVALID_ARGUMENT,
189 _("Meaningless key/value pair combination in address entry '%s'"),
199 is_valid_nonce_tcp (const gchar *address_entry,
200 GHashTable *key_value_pairs,
209 const gchar *nonce_file;
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);
236 G_IO_ERROR_INVALID_ARGUMENT,
237 _("Unsupported key '%s' in address entry '%s'"),
246 port_num = strtol (port, &endp, 10);
247 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
251 G_IO_ERROR_INVALID_ARGUMENT,
252 _("Error in address '%s' - the port attribute is malformed"),
258 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
262 G_IO_ERROR_INVALID_ARGUMENT,
263 _("Error in address '%s' - the family attribute is malformed"),
270 /* TODO: validate host */
273 nonce_file = nonce_file; /* To avoid -Wunused-but-set-variable */
284 is_valid_tcp (const gchar *address_entry,
285 GHashTable *key_value_pairs,
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);
317 G_IO_ERROR_INVALID_ARGUMENT,
318 _("Unsupported key '%s' in address entry '%s'"),
327 port_num = strtol (port, &endp, 10);
328 if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
332 G_IO_ERROR_INVALID_ARGUMENT,
333 _("Error in address '%s' - the port attribute is malformed"),
339 if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
343 G_IO_ERROR_INVALID_ARGUMENT,
344 _("Error in address '%s' - the family attribute is malformed"),
351 /* TODO: validate host */
363 * g_dbus_is_supported_address:
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
371 * Returns: %TRUE if @string is a valid D-Bus address that is
372 * supported by this library, %FALSE if @error is set.
377 g_dbus_is_supported_address (const gchar *string,
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;
396 if (!_g_dbus_address_parse_entry (a[n],
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)
412 g_free (transport_name);
413 g_hash_table_unref (key_value_pairs);
424 g_assert (ret || (!ret && (error == NULL || *error != NULL)));
430 _g_dbus_address_parse_entry (const gchar *address_entry,
431 gchar **out_transport_name,
432 GHashTable **out_key_value_pairs,
436 GHashTable *key_value_pairs;
437 gchar *transport_name;
444 transport_name = NULL;
445 key_value_pairs = NULL;
447 s = strchr (address_entry, ':');
452 G_IO_ERROR_INVALID_ARGUMENT,
453 _("Address element '%s' does not contain a colon (:)"),
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];
468 s = strchr (kv_pair, '=');
473 G_IO_ERROR_INVALID_ARGUMENT,
474 _("Key/Value pair %d, '%s', in address element '%s' does not contain an equal sign"),
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)
487 G_IO_ERROR_INVALID_ARGUMENT,
488 _("Error unescaping key or value in Key/Value pair %d, '%s', in address element '%s'"),
496 g_hash_table_insert (key_value_pairs, key, value);
502 g_strfreev (kv_pairs);
505 if (out_transport_name != NULL)
506 *out_transport_name = transport_name;
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);
516 g_free (transport_name);
517 if (key_value_pairs != NULL)
518 g_hash_table_unref (key_value_pairs);
523 /* ---------------------------------------------------------------------------------------------------- */
526 g_dbus_address_try_connect_one (const gchar *address_entry,
529 GCancellable *cancellable,
532 /* TODO: Declare an extension point called GDBusTransport (or similar)
533 * and move code below to extensions implementing said extension
534 * point. That way we can implement a D-Bus transport over X11 without
535 * making libgio link to libX11...
538 g_dbus_address_connect (const gchar *address_entry,
539 const gchar *transport_name,
541 GHashTable *key_value_pairs,
542 GCancellable *cancellable,
546 GSocketConnectable *connectable;
547 const gchar *nonce_file;
557 else if (kdbus_okay && g_str_equal (transport_name, "kernel"))
559 GKDBusWorker *worker;
562 path = g_hash_table_lookup (key_value_pairs, "path");
566 g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
567 _("Error in address '%s' - the kernel transport requires a path"),
572 worker = g_kdbus_worker_new (path, error);
577 return G_OBJECT (worker);
580 else if (g_strcmp0 (transport_name, "unix") == 0)
583 const gchar *abstract;
584 path = g_hash_table_lookup (key_value_pairs, "path");
585 abstract = g_hash_table_lookup (key_value_pairs, "abstract");
586 if ((path == NULL && abstract == NULL) || (path != NULL && abstract != NULL))
590 G_IO_ERROR_INVALID_ARGUMENT,
591 _("Error in address '%s' - the unix transport requires exactly one of the "
592 "keys 'path' or 'abstract' to be set"),
595 else if (path != NULL)
597 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new (path));
599 else if (abstract != NULL)
601 connectable = G_SOCKET_CONNECTABLE (g_unix_socket_address_new_with_type (abstract,
603 G_UNIX_SOCKET_ADDRESS_ABSTRACT));
607 g_assert_not_reached ();
611 else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
619 is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
621 host = g_hash_table_lookup (key_value_pairs, "host");
626 G_IO_ERROR_INVALID_ARGUMENT,
627 _("Error in address '%s' - the host attribute is missing or malformed"),
632 s = g_hash_table_lookup (key_value_pairs, "port");
635 port = strtol (s, &endp, 10);
636 if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
640 G_IO_ERROR_INVALID_ARGUMENT,
641 _("Error in address '%s' - the port attribute is missing or malformed"),
649 nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
650 if (nonce_file == NULL)
654 G_IO_ERROR_INVALID_ARGUMENT,
655 _("Error in address '%s' - the noncefile attribute is missing or malformed"),
661 /* TODO: deal with family key/value-pair */
662 connectable = g_network_address_new (host, port);
664 else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
666 gchar *autolaunch_address;
667 autolaunch_address = get_session_address_platform_specific (error);
668 if (autolaunch_address != NULL)
670 ret = g_dbus_address_try_connect_one (autolaunch_address, kdbus_okay, NULL, cancellable, error);
671 g_free (autolaunch_address);
676 g_prefix_error (error, _("Error auto-launching: "));
683 G_IO_ERROR_INVALID_ARGUMENT,
684 _("Unknown or unsupported transport '%s' for address '%s'"),
689 if (connectable != NULL)
691 GSocketClient *client;
692 GSocketConnection *connection;
694 g_assert (ret == NULL);
695 client = g_socket_client_new ();
696 connection = g_socket_client_connect (client,
700 g_object_unref (connectable);
701 g_object_unref (client);
702 if (connection == NULL)
705 ret = G_OBJECT (connection);
707 if (nonce_file != NULL)
709 gchar nonce_contents[16 + 1];
710 size_t num_bytes_read;
713 /* be careful to read only 16 bytes - we also check that the file is only 16 bytes long */
714 f = fopen (nonce_file, "rb");
719 G_IO_ERROR_INVALID_ARGUMENT,
720 _("Error opening nonce file '%s': %s"),
723 g_object_unref (ret);
727 num_bytes_read = fread (nonce_contents,
731 if (num_bytes_read != 16)
733 if (num_bytes_read == 0)
737 G_IO_ERROR_INVALID_ARGUMENT,
738 _("Error reading from nonce file '%s': %s"),
746 G_IO_ERROR_INVALID_ARGUMENT,
747 _("Error reading from nonce file '%s', expected 16 bytes, got %d"),
749 (gint) num_bytes_read);
751 g_object_unref (ret);
758 if (!g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (connection)),
765 g_prefix_error (error, _("Error writing contents of nonce file '%s' to stream:"), nonce_file);
766 g_object_unref (ret);
779 g_dbus_address_try_connect_one (const gchar *address_entry,
782 GCancellable *cancellable,
786 GHashTable *key_value_pairs;
787 gchar *transport_name;
791 transport_name = NULL;
792 key_value_pairs = NULL;
794 if (!_g_dbus_address_parse_entry (address_entry,
800 ret = g_dbus_address_connect (address_entry,
809 guid = g_hash_table_lookup (key_value_pairs, "guid");
810 if (guid != NULL && out_guid != NULL)
811 *out_guid = g_strdup (guid);
814 g_free (transport_name);
815 if (key_value_pairs != NULL)
816 g_hash_table_unref (key_value_pairs);
821 /* ---------------------------------------------------------------------------------------------------- */
830 get_stream_data_free (GetStreamData *data)
832 g_free (data->address);
833 if (data->stream != NULL)
834 g_object_unref (data->stream);
840 get_stream_thread_func (GSimpleAsyncResult *res,
842 GCancellable *cancellable)
847 data = g_simple_async_result_get_op_res_gpointer (res);
850 data->stream = g_dbus_address_get_stream_sync (data->address,
854 if (data->stream == NULL)
855 g_simple_async_result_take_error (res, error);
859 * g_dbus_address_get_stream:
860 * @address: A valid D-Bus address.
861 * @cancellable: (allow-none): A #GCancellable or %NULL.
862 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
863 * @user_data: Data to pass to @callback.
865 * Asynchronously connects to an endpoint specified by @address and
866 * sets up the connection so it is in a state to run the client-side
867 * of the D-Bus authentication conversation.
869 * When the operation is finished, @callback will be invoked. You can
870 * then call g_dbus_address_get_stream_finish() to get the result of
873 * This is an asynchronous failable function. See
874 * g_dbus_address_get_stream_sync() for the synchronous version.
879 g_dbus_address_get_stream (const gchar *address,
880 GCancellable *cancellable,
881 GAsyncReadyCallback callback,
884 GSimpleAsyncResult *res;
887 g_return_if_fail (address != NULL);
889 res = g_simple_async_result_new (NULL,
892 g_dbus_address_get_stream);
893 g_simple_async_result_set_check_cancellable (res, cancellable);
894 data = g_new0 (GetStreamData, 1);
895 data->address = g_strdup (address);
896 g_simple_async_result_set_op_res_gpointer (res,
898 (GDestroyNotify) get_stream_data_free);
899 g_simple_async_result_run_in_thread (res,
900 get_stream_thread_func,
903 g_object_unref (res);
907 * g_dbus_address_get_stream_finish:
908 * @res: A #GAsyncResult obtained from the GAsyncReadyCallback passed to g_dbus_address_get_stream().
909 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
910 * @error: Return location for error or %NULL.
912 * Finishes an operation started with g_dbus_address_get_stream().
914 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
919 g_dbus_address_get_stream_finish (GAsyncResult *res,
923 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
927 g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
928 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
930 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_address_get_stream);
934 data = g_simple_async_result_get_op_res_gpointer (simple);
935 if (g_simple_async_result_propagate_error (simple, error))
938 ret = g_object_ref (data->stream);
939 if (out_guid != NULL)
940 *out_guid = g_strdup (data->guid);
947 * g_dbus_address_get_stream_sync:
948 * @address: A valid D-Bus address.
949 * @out_guid: %NULL or return location to store the GUID extracted from @address, if any.
950 * @cancellable: (allow-none): A #GCancellable or %NULL.
951 * @error: Return location for error or %NULL.
953 * Synchronously connects to an endpoint specified by @address and
954 * sets up the connection so it is in a state to run the client-side
955 * of the D-Bus authentication conversation.
957 * This is a synchronous failable function. See
958 * g_dbus_address_get_stream() for the asynchronous version.
960 * Returns: (transfer full): A #GIOStream or %NULL if @error is set.
965 g_dbus_address_get_stream_sync (const gchar *address,
967 GCancellable *cancellable,
972 result = g_dbus_address_get_stream_internal (address, FALSE, out_guid, cancellable, error);
973 g_assert (result == NULL || G_IS_IO_STREAM (result));
976 return G_IO_STREAM (result);
982 g_dbus_address_get_stream_internal (const gchar *address,
985 GCancellable *cancellable,
993 g_return_val_if_fail (address != NULL, NULL);
994 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
999 addr_array = g_strsplit (address, ";", 0);
1000 if (addr_array != NULL && addr_array[0] == NULL)
1002 last_error = g_error_new_literal (G_IO_ERROR,
1003 G_IO_ERROR_INVALID_ARGUMENT,
1004 _("The given address is empty"));
1008 for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
1010 const gchar *addr = addr_array[n];
1014 ret = g_dbus_address_try_connect_one (addr,
1025 g_assert (this_error != NULL);
1026 if (last_error != NULL)
1027 g_error_free (last_error);
1028 last_error = this_error;
1035 if (last_error != NULL)
1036 g_error_free (last_error);
1040 g_assert (last_error != NULL);
1041 g_propagate_error (error, last_error);
1044 g_strfreev (addr_array);
1048 /* ---------------------------------------------------------------------------------------------------- */
1052 get_session_address_dbus_launch (GError **error)
1056 gchar *command_line;
1057 gchar *launch_stdout;
1058 gchar *launch_stderr;
1060 gchar *old_dbus_verbose;
1061 gboolean restore_dbus_verbose;
1065 command_line = NULL;
1066 launch_stdout = NULL;
1067 launch_stderr = NULL;
1068 restore_dbus_verbose = FALSE;
1069 old_dbus_verbose = NULL;
1071 /* Don't run binaries as root if we're setuid. */
1072 if (GLIB_PRIVATE_CALL (g_check_setuid) ())
1074 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1075 _("Cannot spawn a message bus when setuid"));
1079 machine_id = _g_dbus_get_machine_id (error);
1080 if (machine_id == NULL)
1082 g_prefix_error (error, _("Cannot spawn a message bus without a machine-id: "));
1086 /* We're using private libdbus facilities here. When everything
1087 * (X11, Mac OS X, Windows) is spec'ed out correctly (not even the
1088 * X11 property is correctly documented right now) we should
1089 * consider using the spec instead of dbus-launch.
1091 * --autolaunch=MACHINEID
1092 * This option implies that dbus-launch should scan for a previ‐
1093 * ously-started session and reuse the values found there. If no
1094 * session is found, it will start a new session. The --exit-with-
1095 * session option is implied if --autolaunch is given. This option
1096 * is for the exclusive use of libdbus, you do not want to use it
1097 * manually. It may change in the future.
1100 /* TODO: maybe provide a variable for where to look for the dbus-launch binary? */
1101 command_line = g_strdup_printf ("dbus-launch --autolaunch=%s --binary-syntax --close-stderr", machine_id);
1103 if (G_UNLIKELY (_g_dbus_debug_address ()))
1105 _g_dbus_debug_print_lock ();
1106 g_print ("GDBus-debug:Address: Running '%s' to get bus address (possibly autolaunching)\n", command_line);
1107 old_dbus_verbose = g_strdup (g_getenv ("DBUS_VERBOSE"));
1108 restore_dbus_verbose = TRUE;
1109 g_setenv ("DBUS_VERBOSE", "1", TRUE);
1110 _g_dbus_debug_print_unlock ();
1113 if (!g_spawn_command_line_sync (command_line,
1122 if (!g_spawn_check_exit_status (exit_status, error))
1124 g_prefix_error (error, _("Error spawning command line '%s': "), command_line);
1128 /* From the dbus-launch(1) man page:
1130 * --binary-syntax Write to stdout a nul-terminated bus address,
1131 * then the bus PID as a binary integer of size sizeof(pid_t),
1132 * then the bus X window ID as a binary integer of size
1133 * sizeof(long). Integers are in the machine's byte order, not
1134 * network byte order or any other canonical byte order.
1136 ret = g_strdup (launch_stdout);
1139 if (G_UNLIKELY (_g_dbus_debug_address ()))
1142 _g_dbus_debug_print_lock ();
1143 g_print ("GDBus-debug:Address: dbus-launch output:");
1144 if (launch_stdout != NULL)
1146 s = _g_dbus_hexdump (launch_stdout, strlen (launch_stdout) + 1 + sizeof (pid_t) + sizeof (long), 2);
1147 g_print ("\n%s", s);
1152 g_print (" (none)\n");
1154 g_print ("GDBus-debug:Address: dbus-launch stderr output:");
1155 if (launch_stderr != NULL)
1156 g_print ("\n%s", launch_stderr);
1158 g_print (" (none)\n");
1159 _g_dbus_debug_print_unlock ();
1162 g_free (machine_id);
1163 g_free (command_line);
1164 g_free (launch_stdout);
1165 g_free (launch_stderr);
1166 if (G_UNLIKELY (restore_dbus_verbose))
1168 if (old_dbus_verbose != NULL)
1169 g_setenv ("DBUS_VERBOSE", old_dbus_verbose, TRUE);
1171 g_unsetenv ("DBUS_VERBOSE");
1173 g_free (old_dbus_verbose);
1180 #define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
1181 #define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
1182 #define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
1183 #define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
1186 release_mutex (HANDLE mutex)
1188 ReleaseMutex (mutex);
1189 CloseHandle (mutex);
1193 acquire_mutex (const char *mutexname)
1198 mutex = CreateMutexA (NULL, FALSE, mutexname);
1202 res = WaitForSingleObject (mutex, INFINITE);
1205 case WAIT_ABANDONED:
1206 release_mutex (mutex);
1217 is_mutex_owned (const char *mutexname)
1220 gboolean res = FALSE;
1222 mutex = CreateMutexA (NULL, FALSE, mutexname);
1223 if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
1226 ReleaseMutex (mutex);
1227 CloseHandle (mutex);
1233 read_shm (const char *shm_name)
1242 for (i = 0; i < 20; i++)
1244 shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
1245 if (shared_mem != 0)
1250 if (shared_mem != 0)
1252 shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
1253 if (shared_data != NULL)
1255 res = g_strdup (shared_data);
1256 UnmapViewOfFile (shared_data);
1258 CloseHandle (shared_mem);
1265 set_shm (const char *shm_name, const char *value)
1270 shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
1271 0, strlen (value) + 1, shm_name);
1272 if (shared_mem == 0)
1275 shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
1276 if (shared_data == NULL)
1279 strcpy (shared_data, value);
1281 UnmapViewOfFile (shared_data);
1286 /* These keep state between publish_session_bus and unpublish_session_bus */
1287 static HANDLE published_daemon_mutex;
1288 static HANDLE published_shared_mem;
1291 publish_session_bus (const char *address)
1295 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1297 published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
1298 if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
1300 release_mutex (init_mutex);
1301 CloseHandle (published_daemon_mutex);
1302 published_daemon_mutex = NULL;
1306 published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
1307 if (!published_shared_mem)
1309 release_mutex (init_mutex);
1310 CloseHandle (published_daemon_mutex);
1311 published_daemon_mutex = NULL;
1315 release_mutex (init_mutex);
1320 unpublish_session_bus (void)
1324 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1326 CloseHandle (published_shared_mem);
1327 published_shared_mem = NULL;
1329 release_mutex (published_daemon_mutex);
1330 published_daemon_mutex = NULL;
1332 release_mutex (init_mutex);
1336 wait_console_window (void)
1338 FILE *console = fopen ("CONOUT$", "w");
1340 SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
1341 fprintf (console, _("(Type any character to close this window)\n"));
1347 open_console_window (void)
1349 if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
1350 (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
1352 if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
1353 freopen ("CONOUT$", "w", stdout);
1355 if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
1356 freopen ("CONOUT$", "w", stderr);
1358 SetConsoleTitleW (L"gdbus-daemon debug output.");
1360 atexit (wait_console_window);
1364 idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
1366 GMainLoop *loop = user_data;
1367 g_main_loop_quit (loop);
1370 __declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
1372 __declspec(dllexport) void CALLBACK
1373 g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
1375 GDBusDaemon *daemon;
1377 const char *address;
1378 GError *error = NULL;
1380 if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
1381 open_console_window ();
1383 loop = g_main_loop_new (NULL, FALSE);
1385 address = "nonce-tcp:";
1386 daemon = _g_dbus_daemon_new (address, NULL, &error);
1389 g_printerr ("Can't init bus: %s\n", error->message);
1393 g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
1395 if ( publish_session_bus (_g_dbus_daemon_get_address (daemon)))
1397 g_main_loop_run (loop);
1399 unpublish_session_bus ();
1402 g_main_loop_unref (loop);
1403 g_object_unref (daemon);
1407 get_session_address_dbus_launch (GError **error)
1409 HANDLE autolaunch_mutex, init_mutex;
1410 char *address = NULL;
1411 wchar_t gio_path[MAX_PATH+1+200];
1413 autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
1415 init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
1417 if (is_mutex_owned (DBUS_DAEMON_MUTEX))
1418 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1420 release_mutex (init_mutex);
1422 if (address == NULL)
1424 gio_path[MAX_PATH] = 0;
1425 if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
1427 PROCESS_INFORMATION pi = { 0 };
1428 STARTUPINFOW si = { 0 };
1430 wchar_t gio_path_short[MAX_PATH];
1431 wchar_t rundll_path[MAX_PATH*2];
1432 wchar_t args[MAX_PATH*4];
1434 GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
1436 GetWindowsDirectoryW (rundll_path, MAX_PATH);
1437 wcscat (rundll_path, L"\\rundll32.exe");
1438 if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
1440 GetSystemDirectoryW (rundll_path, MAX_PATH);
1441 wcscat (rundll_path, L"\\rundll32.exe");
1444 wcscpy (args, L"\"");
1445 wcscat (args, rundll_path);
1446 wcscat (args, L"\" ");
1447 wcscat (args, gio_path_short);
1448 #if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
1449 wcscat (args, L",g_win32_run_session_bus");
1450 #elif defined (_MSC_VER)
1451 wcscat (args, L",_g_win32_run_session_bus@16");
1453 wcscat (args, L",g_win32_run_session_bus@16");
1456 res = CreateProcessW (rundll_path, args,
1458 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
1459 0, NULL /* TODO: Should be root */,
1462 address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
1466 release_mutex (autolaunch_mutex);
1468 if (address == NULL)
1472 _("Session dbus not running, and autolaunch failed"));
1478 /* ---------------------------------------------------------------------------------------------------- */
1481 get_session_address_platform_specific (GError **error)
1484 #if defined (G_OS_UNIX) || defined(G_OS_WIN32)
1485 /* need to handle OS X in a different way since 'dbus-launch --autolaunch' probably won't work there */
1486 ret = get_session_address_dbus_launch (error);
1488 /* TODO: implement for OS X */
1493 _("Cannot determine session bus address (not implemented for this OS)"));
1498 /* ---------------------------------------------------------------------------------------------------- */
1501 * g_dbus_address_get_for_bus_sync:
1502 * @bus_type: a #GBusType
1503 * @cancellable: (allow-none): a #GCancellable or %NULL
1504 * @error: return location for error or %NULL
1506 * Synchronously looks up the D-Bus address for the well-known message
1507 * bus instance specified by @bus_type. This may involve using various
1508 * platform specific mechanisms.
1510 * Returns: a valid D-Bus address string for @bus_type or %NULL if
1516 g_dbus_address_get_for_bus_sync (GBusType bus_type,
1517 GCancellable *cancellable,
1521 const gchar *system_bus;
1522 const gchar *session_bus;
1523 const gchar *starter_bus;
1524 GError *local_error;
1526 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1531 if (G_UNLIKELY (_g_dbus_debug_address ()))
1534 _g_dbus_debug_print_lock ();
1535 g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
1536 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1537 for (n = 0; n < 3; n++)
1543 case 0: k = "DBUS_SESSION_BUS_ADDRESS"; break;
1544 case 1: k = "DBUS_SYSTEM_BUS_ADDRESS"; break;
1545 case 2: k = "DBUS_STARTER_BUS_TYPE"; break;
1546 default: g_assert_not_reached ();
1549 g_print ("GDBus-debug:Address: env var %s", k);
1551 g_print ("='%s'\n", v);
1553 g_print (" is not set\n");
1555 _g_dbus_debug_print_unlock ();
1560 case G_BUS_TYPE_SYSTEM:
1561 ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
1564 ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
1568 case G_BUS_TYPE_SESSION:
1569 ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
1572 ret = get_session_address_platform_specific (&local_error);
1576 case G_BUS_TYPE_MACHINE:
1577 system_bus = g_getenv ("DBUS_SYSTEM_BUS_ADDRESS");
1578 if (system_bus == NULL)
1579 ret = g_strdup ("kernel:path=/sys/fs/kdbus/0-system/bus;unix:path=/var/run/dbus/system_bus_socket");
1581 ret = g_strdup_printf ("kernel:path=/sys/fs/kdbus/0-system/bus;%s", system_bus);
1584 case G_BUS_TYPE_USER:
1585 session_bus = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
1586 if (session_bus == NULL)
1587 ret = g_strdup_printf ("kernel:path=%s/kdbus;%s", g_get_user_runtime_dir (),
1588 get_session_address_platform_specific (&local_error));
1590 ret = g_strdup_printf ("kernel:path=%s/kdbus;%s", g_get_user_runtime_dir (), session_bus);
1593 case G_BUS_TYPE_STARTER:
1594 starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
1595 if (g_strcmp0 (starter_bus, "session") == 0)
1597 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, cancellable, &local_error);
1600 else if (g_strcmp0 (starter_bus, "system") == 0)
1602 ret = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, cancellable, &local_error);
1607 if (starter_bus != NULL)
1609 g_set_error (&local_error,
1612 _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
1613 " - unknown value '%s'"),
1618 g_set_error_literal (&local_error,
1621 _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
1622 "variable is not set"));
1628 g_set_error (&local_error,
1631 _("Unknown bus type %d"),
1637 if (G_UNLIKELY (_g_dbus_debug_address ()))
1639 _g_dbus_debug_print_lock ();
1642 g_print ("GDBus-debug:Address: Returning address '%s' for bus type '%s'\n",
1644 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type));
1648 g_print ("GDBus-debug:Address: Cannot look-up address bus type '%s': %s\n",
1649 _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type),
1650 local_error ? local_error->message : "");
1652 _g_dbus_debug_print_unlock ();
1655 if (local_error != NULL)
1656 g_propagate_error (error, local_error);
1662 * g_dbus_address_escape_value:
1663 * @string: an unescaped string to be included in a D-Bus address
1664 * as the value in a key-value pair
1666 * Escape @string so it can appear in a D-Bus address as the value
1667 * part of a key-value pair.
1669 * For instance, if @string is "/run/bus-for-:0",
1670 * this function would return "/run/bus-for-%3A0",
1671 * which could be used in a D-Bus address like
1672 * "unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0".
1674 * Returns: (transfer full): a copy of @string with all
1675 * non-optionally-escaped bytes escaped
1680 g_dbus_address_escape_value (const gchar *string)
1685 g_return_val_if_fail (string != NULL, NULL);
1687 /* There will often not be anything needing escaping at all. */
1688 s = g_string_sized_new (strlen (string));
1690 /* D-Bus address escaping is mostly the same as URI escaping... */
1691 g_string_append_uri_escaped (s, string, "\\/", FALSE);
1693 /* ... but '~' is an unreserved character in URIs, but a
1694 * non-optionally-escaped character in D-Bus addresses. */
1695 for (i = 0; i < s->len; i++)
1697 if (G_UNLIKELY (s->str[i] == '~'))
1700 g_string_insert (s, i + 1, "7E");
1705 return g_string_free (s, FALSE);