* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* kind of pitfalls it avoids
* - Export objects before claiming names
* - Talk about auto-starting services (cf. GBusNameWatcherFlags)
- *
- * - use abstract sockets in test code
- * - right now it doesn't work, dbus-daemon(1) fails with
- *
- * /gdbus/connection/filter: Failed to start message bus: Failed to bind
- * socket "/tmp/g-dbus-tests-pid-28531": Address already in use
- * ** WARNING **: Error reading address from dbus daemon, 0 bytes read
- *
- * or similar.
*/
#include "config.h"
#include "giostream.h"
#include "gasyncresult.h"
#include "gtask.h"
+#include "gmarshal-internal.h"
#ifdef G_OS_UNIX
#include "gunixconnection.h"
* The #GDBusConnection type is used for D-Bus connections to remote
* peers such as a message buses. It is a low-level API that offers a
* lot of flexibility. For instance, it lets you establish a connection
- * over any transport that can by represented as an #GIOStream.
+ * over any transport that can by represented as a #GIOStream.
*
* This class is rarely used directly in D-Bus clients. If you are writing
* a D-Bus client, it is often easier to use the g_bus_own_name(),
* ## An example for file descriptor passing # {#gdbus-unix-fd-client}
*
* Here is an example for passing UNIX file descriptors:
- * [gdbus-unix-fd-client.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-unix-fd-client.c)
+ * [gdbus-unix-fd-client.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-unix-fd-client.c)
*
* ## An example for exporting a GObject # {#gdbus-export}
*
else
{
if (alive_connections != NULL)
- g_warn_if_fail (g_hash_table_lookup (alive_connections, connection) == NULL);
+ g_warn_if_fail (!g_hash_table_contains (alive_connections, connection));
}
CONNECTION_UNLOCK (connection);
G_UNLOCK (message_bus_lock);
g_value_set_flags (value, g_dbus_connection_get_capabilities (connection));
break;
+ case PROP_FLAGS:
+ g_value_set_flags (value, g_dbus_connection_get_flags (connection));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
P_("Flags"),
G_TYPE_DBUS_CONNECTION_FLAGS,
G_DBUS_CONNECTION_FLAGS_NONE,
+ G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_STRUCT_OFFSET (GDBusConnectionClass, closed),
NULL,
NULL,
- NULL,
+ _g_cclosure_marshal_VOID__BOOLEAN_BOXED,
G_TYPE_NONE,
2,
G_TYPE_BOOLEAN,
G_TYPE_ERROR);
+ g_signal_set_va_marshaller (signals[CLOSED_SIGNAL],
+ G_TYPE_FROM_CLASS (klass),
+ _g_cclosure_marshal_VOID__BOOLEAN_BOXEDv);
}
static void
return connection->capabilities;
}
+/**
+ * g_dbus_connection_get_flags:
+ * @connection: a #GDBusConnection
+ *
+ * Gets the flags used to construct this connection
+ *
+ * Returns: zero or more flags from the #GDBusConnectionFlags enumeration
+ *
+ * Since: 2.60
+ */
+GDBusConnectionFlags
+g_dbus_connection_get_flags (GDBusConnection *connection)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_DBUS_CONNECTION_FLAGS_NONE);
+
+ /* do not use g_return_val_if_fail(), we want the memory barrier */
+ if (!check_initialized (connection))
+ return G_DBUS_CONNECTION_FLAGS_NONE;
+
+ return connection->flags;
+}
+
/* ---------------------------------------------------------------------------------------------------- */
/* Called in a temporary thread without holding locks. */
* @cancellable: (nullable): a #GCancellable or %NULL
* @error: return location for error or %NULL
*
- * Synchronously closees @connection. The calling thread is blocked
+ * Synchronously closes @connection. The calling thread is blocked
* until this is done. See g_dbus_connection_close() for the
* asynchronous version of this method and more details about what it
* does.
/* ---------------------------------------------------------------------------------------------------- */
-/* can be called from any thread with lock held */
+/* can be called from any thread with lock held; @task is (transfer full) */
static void
send_message_with_reply_cleanup (GTask *task, gboolean remove)
{
/* ---------------------------------------------------------------------------------------------------- */
-/* Called from GDBus worker thread with lock held */
+/* Called from GDBus worker thread with lock held; @task is (transfer full). */
static void
send_message_data_deliver_reply_unlocked (GTask *task,
GDBusMessage *reply)
/* ---------------------------------------------------------------------------------------------------- */
-/* Called from a user thread, lock is not held */
+/* Called from a user thread, lock is not held; @task is (transfer full) */
static gboolean
send_message_with_reply_cancelled_idle_cb (gpointer user_data)
{
/* ---------------------------------------------------------------------------------------------------- */
-/* Called from a user thread, lock is not held */
+/* Called from a user thread, lock is not held; @task is (transfer full) */
static gboolean
send_message_with_reply_timeout_cb (gpointer user_data)
{
g_hash_table_insert (connection->map_method_serial_to_task,
GUINT_TO_POINTER (*out_serial),
- task);
+ g_steal_pointer (&task));
}
/**
gboolean alive;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
GUINT_TO_POINTER (reply_serial));
if (task != NULL)
{
+ /* This removes @task from @map_method_serial_to_task. */
//g_debug ("delivering reply/error for serial %d for %p", reply_serial, connection);
send_message_data_deliver_reply_unlocked (task, message);
}
gboolean alive;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
guint old_atomic_flags;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
G_LOCK (message_bus_lock);
if (alive_connections == NULL)
alive_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
- g_hash_table_insert (alive_connections, connection, connection);
+ g_hash_table_add (alive_connections, connection);
G_UNLOCK (message_bus_lock);
connection->worker = _g_dbus_worker_new (connection->stream,
* then call g_dbus_connection_new_finish() to get the result of the
* operation.
*
- * This is a asynchronous failable constructor. See
+ * This is an asynchronous failable constructor. See
* g_dbus_connection_new_sync() for the synchronous
* version.
*
GAsyncReadyCallback callback,
gpointer user_data)
{
+ _g_dbus_initialize ();
+
g_return_if_fail (G_IS_IO_STREAM (stream));
+
g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
G_PRIORITY_DEFAULT,
cancellable,
GCancellable *cancellable,
GError **error)
{
+ _g_dbus_initialize ();
g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_initable_new (G_TYPE_DBUS_CONNECTION,
* %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS flags.
*
* When the operation is finished, @callback will be invoked. You can
- * then call g_dbus_connection_new_finish() to get the result of the
- * operation.
+ * then call g_dbus_connection_new_for_address_finish() to get the result of
+ * the operation.
*
* If @observer is not %NULL it may be used to control the
* authentication process.
*
- * This is a asynchronous failable constructor. See
+ * This is an asynchronous failable constructor. See
* g_dbus_connection_new_for_address_sync() for the synchronous
* version.
*
GAsyncReadyCallback callback,
gpointer user_data)
{
+ _g_dbus_initialize ();
+
g_return_if_fail (address != NULL);
+
g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
G_PRIORITY_DEFAULT,
cancellable,
GCancellable *cancellable,
GError **error)
{
+ _g_dbus_initialize ();
+
g_return_val_if_fail (address != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_initable_new (G_TYPE_DBUS_CONNECTION,
* more details.
*
* Note that this function should be used with care. Most modern UNIX
- * desktops tie the notion of a user session the session bus, and expect
- * all of a users applications to quit when their bus connection goes away.
+ * desktops tie the notion of a user session with the session bus, and expect
+ * all of a user's applications to quit when their bus connection goes away.
* If you are setting @exit_on_close to %FALSE for the shared session
* bus connection, you should make sure that your application exits
* when the user session ends.
* bus. This can also be used to figure out if @connection is a
* message bus connection.
*
- * Returns: the unique name or %NULL if @connection is not a message
+ * Returns: (nullable): the unique name or %NULL if @connection is not a message
* bus connection. Do not free this string, it is owned by
* @connection.
*
* dispatched anywhere else - not even the standard dispatch machinery
* (that API such as g_dbus_connection_signal_subscribe() and
* g_dbus_connection_send_message_with_reply() relies on) will see the
- * message. Similary, if a filter consumes an outgoing message, the
+ * message. Similarly, if a filter consumes an outgoing message, the
* message will not be sent to the other peer.
*
* If @user_data_free_func is non-%NULL, it will be called (in the
guint filter_id)
{
guint n;
+ gboolean found;
FilterData *to_destroy;
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
g_return_if_fail (check_initialized (connection));
CONNECTION_LOCK (connection);
+ found = FALSE;
to_destroy = NULL;
for (n = 0; n < connection->filters->len; n++)
{
FilterData *data = connection->filters->pdata[n];
if (data->id == filter_id)
{
+ found = TRUE;
g_ptr_array_remove_index (connection->filters, n);
data->ref_count--;
if (data->ref_count == 0)
g_main_context_unref (to_destroy->context);
g_free (to_destroy);
}
- else
+ else if (!found)
{
g_warning ("g_dbus_connection_remove_filter: No filter found for filter_id %d", filter_id);
}
* signal is unsubscribed from, and may be called after @connection
* has been destroyed.)
*
+ * The returned subscription identifier is an opaque value which is guaranteed
+ * to never be zero.
+ *
+ * This function can never fail.
+ *
* Returns: a subscription identifier that can be used with g_dbus_connection_signal_unsubscribe()
*
* Since: 2.26
{
reply = g_dbus_message_new_method_error (data->message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface 'org.freedesktop.DBus.Properties' on object at path %s"),
+ _("No such interface “org.freedesktop.DBus.Properties” on object at path %s"),
g_dbus_message_get_path (data->message));
g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such property '%s'"),
+ _("No such property “%s”"),
property_name);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Property '%s' is not readable"),
+ _("Property “%s” is not readable"),
property_name);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Property '%s' is not writable"),
+ _("Property “%s” is not writable"),
property_name);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Error setting property '%s': Expected type '%s' but got '%s'"),
+ _("Error setting property “%s”: Expected type “%s” but got “%s”"),
property_name, property_info->signature,
g_variant_get_type_string (value));
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such interface '%s'"),
+ _("No such interface “%s”"),
interface_name);
g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
{
reply = g_dbus_message_new_method_error (data->message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface 'org.freedesktop.DBus.Properties' on object at path %s"),
+ _("No such interface “org.freedesktop.DBus.Properties” on object at path %s"),
g_dbus_message_get_path (data->message));
g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such interface '%s'"),
+ _("No such interface “%s”"),
interface_name);
g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
else
s = g_strdup (begin);
- if (g_hash_table_lookup (set, s) == NULL)
- g_hash_table_insert (set, s, GUINT_TO_POINTER (1));
+ if (!g_hash_table_contains (set, s))
+ g_hash_table_add (set, s);
else
g_free (s);
}
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (g_dbus_method_invocation_get_message (invocation),
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface '%s' on object at path %s"),
+ _("No such interface “%s” on object at path %s"),
g_dbus_method_invocation_get_interface_name (invocation),
g_dbus_method_invocation_get_object_path (invocation));
g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
call_in_idle_cb,
invocation,
g_object_unref);
- g_source_set_name (idle_source, "[gio] call_in_idle_cb");
+ g_source_set_name (idle_source, "[gio, " __FILE__ "] call_in_idle_cb");
g_source_attach (idle_source, main_context);
g_source_unref (idle_source);
}
{
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such method '%s'"),
+ _("No such method “%s”"),
g_dbus_message_get_member (message));
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("Type of message, '%s', does not match expected type '%s'"),
+ _("Type of message, “%s”, does not match expected type “%s”"),
g_variant_get_type_string (parameters),
type_string);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
*
* If the parameters GVariant is floating, it is consumed.
*
- * This can only fail if @parameters is not compatible with the D-Bus protocol.
+ * This can only fail if @parameters is not compatible with the D-Bus protocol
+ * (%G_IO_ERROR_INVALID_ARGUMENT), or if @connection has been closed
+ * (%G_IO_ERROR_CLOSED).
*
* Returns: %TRUE unless @error is set
*
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
- _("Method '%s' returned type '%s', but expected '%s'"),
+ _("Method “%s” returned type “%s”, but expected “%s”"),
method_name, g_variant_get_type_string (result), type_string);
g_variant_unref (result);
{
GVariantType *reply_type;
gchar *method_name; /* for error message */
- guint32 serial;
GUnixFDList *fd_list;
} CallState;
" <<<< ASYNC COMPLETE %s() (serial %d)\n"
" ",
state->method_name,
- state->serial);
+ g_dbus_message_get_reply_serial (reply));
if (reply != NULL)
{
g_print ("SUCCESS\n");
message,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
timeout_msec,
- &state->serial,
+ &serial,
cancellable,
g_dbus_connection_call_done,
task);
- serial = state->serial;
}
else
{
* @method_name: the name of the method to invoke
* @parameters: (nullable): a #GVariant tuple with parameters for the method
* or %NULL if not passing parameters
- * @reply_type: (nullable): the expected type of the reply, or %NULL
+ * @reply_type: (nullable): the expected type of the reply (which will be a
+ * tuple), or %NULL
* @flags: flags from the #GDBusCallFlags enumeration
* @timeout_msec: the timeout in milliseconds, -1 to use the default
* timeout or %G_MAXINT for no timeout
*
* If @reply_type is non-%NULL then the reply will be checked for having this type and an
* error will be raised if it does not match. Said another way, if you give a @reply_type
- * then any non-%NULL return value will be of this type.
+ * then any non-%NULL return value will be of this type. Unless it’s
+ * %G_VARIANT_TYPE_UNIT, the @reply_type will be a tuple containing one or more
+ * values.
*
* If the @parameters #GVariant is floating, it is consumed. This allows
* convenient 'inline' use of g_variant_new(), e.g.:
* operation will fail with %G_IO_ERROR_CANCELLED. If @parameters
* contains a value not compatible with the D-Bus protocol, the operation
* fails with %G_IO_ERROR_INVALID_ARGUMENT.
-
+ *
* If @reply_type is non-%NULL then the reply will be checked for having
* this type and an error will be raised if it does not match. Said
* another way, if you give a @reply_type then any non-%NULL return
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.InvalidArgs",
- _("No such interface '%s'"),
+ _("No such interface “%s”"),
interface_name);
g_dbus_connection_send_message (es->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
g_object_unref (reply);
GDBusMessage *reply;
reply = g_dbus_message_new_method_error (data->message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("Method '%s' on interface '%s' with signature '%s' does not exist"),
+ _("Method “%s” on interface “%s” with signature “%s” does not exist"),
g_dbus_message_get_member (data->message),
g_dbus_message_get_interface (data->message),
g_dbus_message_get_signature (data->message));
/* if we end up here, the message has not been not handled - so return an error saying this */
reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface '%s' on object at path %s"),
+ _("No such interface “%s” on object at path %s"),
interface_name,
object_path);
g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
G_IO_ERROR,
G_IO_ERROR_INVALID_ARGUMENT,
_("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
- " - unknown value '%s'"),
+ " — unknown value “%s”"),
starter_bus);
}
else
return ret;
}
+/* May be called from any thread. Must not hold message_bus_lock. */
+void
+_g_bus_forget_singleton (GBusType bus_type)
+{
+ GWeakRef *singleton;
+
+ G_LOCK (message_bus_lock);
+
+ singleton = message_bus_get_singleton (bus_type, NULL);
+
+ if (singleton != NULL)
+ g_weak_ref_set (singleton, NULL);
+
+ G_UNLOCK (message_bus_lock);
+}
+
/**
* g_bus_get_sync:
* @bus_type: a #GBusType
{
GDBusConnection *connection;
+ _g_dbus_initialize ();
+
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
connection = get_uninitialized_connection (bus_type, cancellable, error);
* When the operation is finished, @callback will be invoked. You can
* then call g_bus_get_finish() to get the result of the operation.
*
- * This is a asynchronous failable function. See g_bus_get_sync() for
+ * This is an asynchronous failable function. See g_bus_get_sync() for
* the synchronous version.
*
* Since: 2.26
GTask *task;
GError *error = NULL;
+ _g_dbus_initialize ();
+
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, g_bus_get);