g_dbus_connection_send_message_with_reply
g_dbus_connection_send_message_with_reply_finish
g_dbus_connection_send_message_with_reply_sync
-GDBusMessageFilterResult
GDBusMessageFilterFunction
g_dbus_connection_add_filter
g_dbus_connection_remove_filter
g_dbus_message_set_serial (message, serial_to_use);
+ g_dbus_message_lock (message);
_g_dbus_worker_send_message (connection->worker,
message,
(gchar*) blob,
* linkend="gdbus-unix-fd-client"/> for an example of how to use this
* low-level API to send and receive UNIX file descriptors.
*
+ * Note that @message must be unlocked, unless @flags contain the
+ * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
+ *
* Returns: %TRUE if the message was well-formed and queued for
* transmission, %FALSE if @error is set.
*
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
+ g_return_val_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
CONNECTION_LOCK (connection);
* g_dbus_connection_send_message_with_reply_finish() to get the result of the operation.
* See g_dbus_connection_send_message_with_reply_sync() for the synchronous version.
*
+ * Note that @message must be unlocked, unless @flags contain the
+ * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
+ *
* See <xref linkend="gdbus-server"/> and <xref
* linkend="gdbus-unix-fd-client"/> for an example of how to use this
* low-level API to send and receive UNIX file descriptors.
{
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
g_return_if_fail (G_IS_DBUS_MESSAGE (message));
+ g_return_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message));
g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
CONNECTION_LOCK (connection);
* linkend="gdbus-unix-fd-client"/> for an example of how to use this
* low-level API to send and receive UNIX file descriptors.
*
- * Returns: A #GDBusMessage or %NULL if @error is set.
+ * Returns: A locked #GDBusMessage or %NULL if @error is set.
*
* Since: 2.26
*/
* linkend="gdbus-unix-fd-client"/> for an example of how to use this
* low-level API to send and receive UNIX file descriptors.
*
- * Returns: A #GDBusMessage that is the reply to @message or %NULL if @error is set.
+ * Note that @message must be unlocked, unless @flags contain the
+ * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
+ *
+ * Returns: A locked #GDBusMessage that is the reply to @message or %NULL if @error is set.
*
* Since: 2.26
*/
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
+ g_return_val_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message), FALSE);
g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
//g_debug ("in on_worker_message_received");
+ g_object_ref (message);
+ g_dbus_message_lock (message);
+
g_object_ref (connection);
/* First collect the set of callback functions */
}
CONNECTION_UNLOCK (connection);
- /* the call the filters in order (without holding the lock) */
+ /* then call the filters in order (without holding the lock) */
consumed_by_filter = FALSE;
altered_by_filter = FALSE;
for (n = 0; n < num_filters; n++)
{
- GDBusMessageFilterResult result;
- result = filters[n].func (connection,
- message,
- TRUE,
- filters[n].user_data);
- switch (result)
- {
- case G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT:
- /* do nothing */
- break;
-
- default:
- g_warning ("Treating unknown value %d for GDBusMessageFilterResult from filter "
- "function on incoming message as MESSAGE_CONSUMED.", result);
- /* explicit fallthrough */
- case G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_CONSUMED:
- consumed_by_filter = TRUE;
- break;
-
- case G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED:
- altered_by_filter = TRUE;
- break;
- }
- if (consumed_by_filter)
+ message = filters[n].func (connection,
+ message,
+ TRUE,
+ filters[n].user_data);
+ if (message == NULL)
break;
+ g_dbus_message_lock (message);
}
/* Standard dispatch unless the filter ate the message - no need to
* do anything if the message was altered
*/
- if (!consumed_by_filter)
+ if (message != NULL)
{
GDBusMessageType message_type;
}
}
+ if (message != NULL)
+ g_object_unref (message);
g_object_unref (connection);
g_free (filters);
}
/* Called in worker's thread */
-static GDBusMessageFilterResult
+static GDBusMessage *
on_worker_message_about_to_be_sent (GDBusWorker *worker,
GDBusMessage *message,
gpointer user_data)
FilterCallback *filters;
guint num_filters;
guint n;
- GDBusMessageFilterResult ret;
//g_debug ("in on_worker_message_about_to_be_sent");
-
- ret = G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT;
-
g_object_ref (connection);
/* First collect the set of callback functions */
/* then call the filters in order (without holding the lock) */
for (n = 0; n < num_filters; n++)
{
- GDBusMessageFilterResult result;
- result = filters[n].func (connection,
- message,
- FALSE,
- filters[n].user_data);
- switch (result)
- {
- case G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT:
- /* do nothing, ret might already be _ALTERED */
- break;
-
- default:
- g_warning ("Treating unknown value %d for GDBusMessageFilterResult from filter "
- "function on outgoing message as MESSAGE_CONSUMED.", result);
- /* explicit fallthrough */
- case G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_CONSUMED:
- ret = G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_CONSUMED;
- goto out;
-
- case G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED:
- ret = G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED;
- break;
- }
+ g_dbus_message_lock (message);
+ message = filters[n].func (connection,
+ message,
+ FALSE,
+ filters[n].user_data);
+ if (message == NULL)
+ break;
}
- out:
g_object_unref (connection);
g_free (filters);
- return ret;
+ return message;
}
/* Called in worker's thread - we must not block */
/**
* GDBusMessageFilterFunction:
- * @connection: A #GDBusConnection.
- * @message: A #GDBusMessage.
+ * @connection: (transfer none): A #GDBusConnection.
+ * @message: (transfer full): A locked #GDBusMessage that the filter function takes ownership of.
* @incoming: %TRUE if it is a message received from the other peer, %FALSE if it is
* a message to be sent to the other peer.
* @user_data: User data passed when adding the filter.
*
* Signature for function used in g_dbus_connection_add_filter().
*
- * If you modify an outgoing message, make sure to return
- * %G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED instead of
- * %G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT so the message can be
- * re-serialized. If an error occurs during re-serialization, a
- * warning will be printed on standard error.
- *
- * Returns: A value from the #GDBusMessageFilterResult enumeration
- * describing what to do with @message.
+ * A filter function is passed a #GDBusMessage and expected to return
+ * a #GDBusMessage too. Passive filter functions that don't modify the
+ * message can simply return the @message object:
+ * |[
+ * static GDBusMessage *
+ * passive_filter (GDBusConnection *connection
+ * GDBusMessage *message,
+ * gboolean incoming,
+ * gpointer user_data)
+ * {
+ * /<!-- -->* inspect @message *<!-- -->/
+ * return message;
+ * }
+ * ]|
+ * Filter functions that wants to drop a message can simply return %NULL:
+ * |[
+ * static GDBusMessage *
+ * drop_filter (GDBusConnection *connection
+ * GDBusMessage *message,
+ * gboolean incoming,
+ * gpointer user_data)
+ * {
+ * if (should_drop_message)
+ * {
+ * g_object_unref (message);
+ * message = NULL;
+ * }
+ * return message;
+ * }
+ * ]|
+ * Finally, a filter function may modify a message by copying it:
+ * |[
+ * static GDBusMessage *
+ * modifying_filter (GDBusConnection *connection
+ * GDBusMessage *message,
+ * gboolean incoming,
+ * gpointer user_data)
+ * {
+ * GDBusMessage *copy;
+ * GError *error;
+ *
+ * error = NULL;
+ * copy = g_dbus_message_copy (message, &error);
+ * /<!-- -->* handle @error being is set *<!-- -->/
+ * g_object_unref (message);
+ *
+ * /<!-- -->* modify @copy *<!-- -->/
+ *
+ * return copy;
+ * }
+ * ]|
+ * If the returned #GDBusMessage is different from @message and the
+ * serial number is unset (e.g. zero), then @message's serial number
+ * will be used on the returned message (so in this case the returned
+ * message must be unlocked). Additionally, if the returned message
+ * cannot be sent on @connection, then a warning is logged to
+ * <emphasis>standard error</emphasis>.
+ *
+ * Returns: (transfer full) (allow-none): A #GDBusMessage that will be freed with
+ * g_object_unref() or %NULL to drop the message. Passive filter
+ * functions can simply return the passed @message object.
*
* Since: 2.26
*/
-typedef GDBusMessageFilterResult (*GDBusMessageFilterFunction) (GDBusConnection *connection,
- GDBusMessage *message,
- gboolean incoming,
- gpointer user_data);
+typedef GDBusMessage *(*GDBusMessageFilterFunction) (GDBusConnection *connection,
+ GDBusMessage *message,
+ gboolean incoming,
+ gpointer user_data);
guint g_dbus_connection_add_filter (GDBusConnection *connection,
GDBusMessageFilterFunction filter_function,
worker->message_received_callback (worker, message, worker->user_data);
}
-static GDBusMessageFilterResult
+static GDBusMessage *
_g_dbus_worker_emit_message_about_to_be_sent (GDBusWorker *worker,
GDBusMessage *message)
{
- GDBusMessageFilterResult ret;
- ret = G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT;
+ GDBusMessage *ret;
if (!worker->stopped)
ret = worker->message_about_to_be_sent_callback (worker, message, worker->user_data);
+ else
+ ret = message;
return ret;
}
*/
if (data != NULL)
{
- GDBusMessageFilterResult filter_result;
+ guint32 old_serial;
+ GDBusMessage *old_message;
guchar *new_blob;
gsize new_blob_size;
GError *error;
- filter_result = _g_dbus_worker_emit_message_about_to_be_sent (worker, data->message);
- switch (filter_result)
+ old_message = data->message;
+ old_serial = g_dbus_message_get_serial (old_message);
+ data->message = _g_dbus_worker_emit_message_about_to_be_sent (worker, data->message);
+ if (data->message == old_message)
{
- case G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT:
- /* do nothing */
- break;
-
- case G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_CONSUMED:
- /* drop message */
+ /* filters had no effect - do nothing */
+ }
+ else if (data->message == NULL)
+ {
+ /* filters dropped message */
g_mutex_lock (worker->write_lock);
worker->num_writes_pending -= 1;
g_mutex_unlock (worker->write_lock);
message_to_write_data_free (data);
goto write_next;
+ }
+ else
+ {
+ /* filters altered the message -> reencode */
+
+ if (g_dbus_message_get_serial (data->message) == 0)
+ g_dbus_message_set_serial (data->message, old_serial);
- case G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED:
- /* reencode altered message */
error = NULL;
new_blob = g_dbus_message_to_blob (data->message,
&new_blob_size,
data->blob = (gchar *) new_blob;
data->blob_size = new_blob_size;
}
- break;
}
write_message_async (worker,
GDBusMessage *message,
gpointer user_data);
-typedef GDBusMessageFilterResult (*GDBusWorkerMessageAboutToBeSentCallback) (GDBusWorker *worker,
- GDBusMessage *message,
- gpointer user_data);
+typedef GDBusMessage *(*GDBusWorkerMessageAboutToBeSentCallback) (GDBusWorker *worker,
+ GDBusMessage *message,
+ gpointer user_data);
typedef void (*GDBusWorkerDisconnectedCallback) (GDBusWorker *worker,
gboolean remote_peer_vanished,
G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN = 'l'
} GDBusMessageByteOrder;
-/**
- * GDBusMessageFilterResult:
- * @G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT: The filter function had
- * no effect on the message - the message will be passed on to the
- * next filter function and/or sent to the remote peer.
- * @G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_CONSUMED: The message was
- * consumed by the filter function and will be dropped - the message
- * will not be passed to other filter functions and/or sent to the
- * remote peer.
- * @G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED: The message was
- * modified - the message will still be passed on to the next filter
- * function and/or sent to the remote peer.
- *
- * Possible return values for #GDBusMessageFilterFunction when
- * handling a #GDBusMessage.
- *
- * Since: 2.26
- */
-typedef enum
-{
- G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT,
- G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_CONSUMED,
- G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED
-} GDBusMessageFilterResult;
-
G_END_DECLS
#endif /* __GIO_ENUMS_H__ */
NULL /* _set_property */
};
-static GDBusMessageFilterResult
+static GDBusMessage *
some_filter_func (GDBusConnection *connection,
GDBusMessage *message,
gboolean incoming,
gpointer user_data)
{
- return G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT;
+ return message;
}
static void
guint32 serial;
} FilterData;
-static GDBusMessageFilterResult
+static GDBusMessage *
filter_func (GDBusConnection *connection,
GDBusMessage *message,
gboolean incoming,
data->num_outgoing += 1;
}
- return G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT;
+ return message;
}
+
typedef struct
{
- GDBusMessageFilterResult incoming;
- GDBusMessageFilterResult outgoing;
+ gboolean alter_incoming;
+ gboolean alter_outgoing;
} FilterEffects;
-static GDBusMessageFilterResult
+static GDBusMessage *
other_filter_func (GDBusConnection *connection,
GDBusMessage *message,
gboolean incoming,
gpointer user_data)
{
FilterEffects *effects = user_data;
- GDBusMessageFilterResult ret;
+ GDBusMessage *ret;
+ gboolean alter;
if (incoming)
- ret = effects->incoming;
+ alter = effects->alter_incoming;
else
- ret = effects->outgoing;
+ alter = effects->alter_outgoing;
- if (ret == G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED)
+ if (alter)
{
+ GDBusMessage *copy;
GVariant *body;
gchar *s;
gchar *s2;
- body = g_dbus_message_get_body (message);
+
+ copy = g_dbus_message_copy (message, NULL);
+ g_object_unref (message);
+
+ body = g_dbus_message_get_body (copy);
g_variant_get (body, "(s)", &s);
s2 = g_strdup_printf ("MOD: %s", s);
- g_dbus_message_set_body (message, g_variant_new ("(s)", s2));
+ g_dbus_message_set_body (copy, g_variant_new ("(s)", s2));
g_free (s2);
g_free (s);
+
+ ret = copy;
+ }
+ else
+ {
+ ret = message;
}
return ret;
GDBusConnection *c;
FilterData data;
GDBusMessage *m;
+ GDBusMessage *m2;
GDBusMessage *r;
GError *error;
guint filter_id;
while (data.num_handled == 0)
g_thread_yield ();
- g_dbus_message_set_serial (m, 0);
- g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
+ m2 = g_dbus_message_copy (m, &error);
+ g_assert_no_error (error);
+ g_dbus_connection_send_message (c, m2, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
+ g_object_unref (m2);
g_assert_no_error (error);
while (data.num_handled == 1)
g_thread_yield ();
- g_dbus_message_set_serial (m, 0);
+ m2 = g_dbus_message_copy (m, &error);
+ g_assert_no_error (error);
r = g_dbus_connection_send_message_with_reply_sync (c,
- m,
+ m2,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-1,
&data.serial,
NULL, /* GCancellable */
&error);
+ g_object_unref (m2);
g_assert_no_error (error);
g_assert (r != NULL);
g_object_unref (r);
g_dbus_connection_remove_filter (c, filter_id);
- g_dbus_message_set_serial (m, 0);
+ m2 = g_dbus_message_copy (m, &error);
+ g_assert_no_error (error);
r = g_dbus_connection_send_message_with_reply_sync (c,
- m,
+ m2,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-1,
&data.serial,
NULL, /* GCancellable */
&error);
+ g_object_unref (m2);
g_assert_no_error (error);
g_assert (r != NULL);
g_object_unref (r);
g_source_remove (timeout_mainloop_id);
g_dbus_connection_signal_unsubscribe (c, signal_handler_id);
- /* now test all nine combinations... */
-
+ /* now test some combinations... */
filter_id = g_dbus_connection_add_filter (c,
other_filter_func,
&effects,
NULL);
/* -- */
- effects.incoming = G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT;
- effects.outgoing = G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT;
+ effects.alter_incoming = FALSE;
+ effects.alter_outgoing = FALSE;
error = NULL;
result = g_dbus_connection_call_sync (c,
"com.example.TestService", /* bus name */
g_assert_cmpstr (s, ==, "You greeted me with 'Cat'. Thanks!");
g_variant_unref (result);
/* -- */
- effects.incoming = G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED;
- effects.outgoing = G_DBUS_MESSAGE_FILTER_RESULT_MESSAGE_ALTERED;
+ effects.alter_incoming = TRUE;
+ effects.alter_outgoing = TRUE;
error = NULL;
result = g_dbus_connection_call_sync (c,
"com.example.TestService", /* bus name */
#define OVERFLOW_NUM_SIGNALS 5000
#define OVERFLOW_TIMEOUT_SEC 10
-static GDBusMessageFilterResult
+static GDBusMessage *
overflow_filter_func (GDBusConnection *connection,
GDBusMessage *message,
gboolean incoming,
{
volatile gint *counter = user_data;
*counter += 1;
- return G_DBUS_MESSAGE_FILTER_RESULT_NO_EFFECT;
+ return message;
}
static gboolean