*/
dbus_bool_t dispatch_acquired; /**< Someone has dispatch path (can drain incoming queue) */
dbus_bool_t io_path_acquired; /**< Someone has transport io path (can use the transport to read/write messages) */
-
+
+ unsigned int dispatch_disabled : 1; /**< if true, then dispatching incoming messages is stopped until enabled again */
unsigned int shareable : 1; /**< #TRUE if libdbus owns a reference to the connection and can return it from dbus_connection_open() more than once */
unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */
(*connection->wakeup_main_function) (connection->wakeup_main_data);
}
+static void
+_dbus_connection_set_dispatch(DBusConnection *connection,
+ dbus_bool_t disabled)
+{
+ CONNECTION_LOCK (connection);
+ if (connection->dispatch_disabled != disabled)
+ {
+ DBusDispatchStatus status;
+
+ connection->dispatch_disabled = disabled;
+ status = _dbus_connection_get_dispatch_status_unlocked (connection);
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
+ }
+ else
+ {
+ CONNECTION_UNLOCK (connection);
+ }
+}
+
+
+void
+_dbus_connection_enable_dispatch (DBusConnection *connection)
+{
+ _dbus_connection_set_dispatch (connection, FALSE);
+}
+
+void
+ _dbus_connection_disable_dispatch (DBusConnection *connection)
+{
+ _dbus_connection_set_dispatch (connection, TRUE);
+}
+
+
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
/**
* Gets the locks so we can examine them
_dbus_connection_queue_synthesized_message_link (DBusConnection *connection,
DBusList *link)
{
+ DBusMessage *msg, *rmsg;
+
HAVE_LOCK_CHECK (connection);
-
+
+ msg = (DBusMessage *)link->data;
+
+ rmsg = msg;
+ if (_dbus_transport_assure_protocol_version (connection->transport, &rmsg))
+ {
+ /* If the message is converted, then we don't need the old format anymore */
+ _dbus_list_free_link(link);
+ link = _dbus_list_alloc_link (rmsg);
+ dbus_message_unref (msg);
+ }
+
_dbus_list_append_link (&connection->incoming_messages, link);
connection->n_incoming += 1;
{
dbus_uint32_t serial;
+ /* Finish preparing the message */
+ if (dbus_message_get_serial (message) == 0)
+ {
+ serial = _dbus_connection_get_next_client_serial (connection);
+ dbus_message_set_serial (message, serial);
+ if (client_serial)
+ *client_serial = serial;
+ }
+ else
+ {
+ if (client_serial)
+ *client_serial = dbus_message_get_serial (message);
+ }
+
+ _dbus_verbose ("Message %p serial is %u\n",
+ message, dbus_message_get_serial (message));
+
+ dbus_message_lock (message);
+
+ /* This converts message if neccessary */
+ if (!_dbus_transport_assure_protocol_version (connection->transport, &message))
+ {
+ /* Only non-converted messages must be refed.
+ * Converted messages are local anyway.
+ */
+ dbus_message_ref (message);
+ }
+
preallocated->queue_link->data = message;
_dbus_list_prepend_link (&connection->outgoing_messages,
preallocated->queue_link);
dbus_free (preallocated);
preallocated = NULL;
- dbus_message_ref (message);
-
connection->n_outgoing += 1;
_dbus_verbose ("Message %p (%s %s %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n",
connection,
connection->n_outgoing);
- if (dbus_message_get_serial (message) == 0)
- {
- serial = _dbus_connection_get_next_client_serial (connection);
- dbus_message_set_serial (message, serial);
- if (client_serial)
- *client_serial = serial;
- }
- else
- {
- if (client_serial)
- *client_serial = dbus_message_get_serial (message);
- }
-
- _dbus_verbose ("Message %p serial is %u\n",
- message, dbus_message_get_serial (message));
-
- dbus_message_lock (message);
-
/* Now we need to run an iteration to hopefully just write the messages
* out immediately, and otherwise get them queued up
*/
_dbus_sleep_milliseconds (1000);
}
-static DBusMessage *
-generate_local_error_message (dbus_uint32_t serial,
- char *error_name,
- char *error_msg)
-{
- DBusMessage *message;
- message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
- if (!message)
- goto out;
-
- if (!dbus_message_set_error_name (message, error_name))
- {
- dbus_message_unref (message);
- message = NULL;
- goto out;
- }
-
- dbus_message_set_no_reply (message, TRUE);
-
- if (!dbus_message_set_reply_serial (message,
- serial))
- {
- dbus_message_unref (message);
- message = NULL;
- goto out;
- }
-
- if (error_msg != NULL)
- {
- DBusMessageIter iter;
-
- dbus_message_iter_init_append (message, &iter);
- if (!dbus_message_iter_append_basic (&iter,
- DBUS_TYPE_STRING,
- &error_msg))
- {
- dbus_message_unref (message);
- message = NULL;
- goto out;
- }
- }
-
- out:
- return message;
-}
-
/*
* Peek the incoming queue to see if we got reply for a specific serial
*/
{
_dbus_pending_call_set_reply_unlocked (pending, message);
_dbus_pending_call_ref_unlocked (pending); /* in case there's no app with a ref held */
+ _dbus_pending_call_start_completion_unlocked(pending);
_dbus_connection_detach_pending_call_and_unlock (connection, pending);
-
+
/* Must be called unlocked since it invokes app callback */
- _dbus_pending_call_complete (pending);
+ _dbus_pending_call_finish_completion (pending);
dbus_pending_call_unref (pending);
}
{
DBusMessage *error_msg;
- error_msg = generate_local_error_message (client_serial,
- DBUS_ERROR_DISCONNECTED,
- "Connection was disconnected before a reply was received");
+ error_msg = _dbus_generate_local_error_message (client_serial,
+ DBUS_ERROR_DISCONNECTED,
+ "Connection was disconnected before a reply was received");
/* on OOM error_msg is set to NULL */
complete_pending_call_and_unlock (connection, pending, error_msg);
+ if (error_msg != NULL)
+ dbus_message_unref (error_msg);
dbus_pending_call_unref (pending);
return;
}
{
/* block again, we don't have the reply buffered yet. */
_dbus_connection_do_iteration_unlocked (connection,
- NULL,
+ pending,
DBUS_ITERATION_DO_READING |
DBUS_ITERATION_BLOCK,
timeout_milliseconds - elapsed_milliseconds);
_dbus_hash_table_unref (connection->pending_replies);
connection->pending_replies = NULL;
- _dbus_list_clear (&connection->filter_list);
-
_dbus_list_foreach (&connection->outgoing_messages,
free_outgoing_message,
connection);
_dbus_rmutex_free_at_location (&connection->slot_mutex);
_dbus_rmutex_free_at_location (&connection->mutex);
-
+
dbus_free (connection);
}
* dbus_bus_get_id() instead (which is just a convenience wrapper
* around the org.freedesktop.DBus.GetId method invoked on the bus).
*
- * You can also get a machine ID; see dbus_get_local_machine_id() to
+ * You can also get a machine ID; see dbus_try_get_local_machine_id() to
* get the machine you are on. There isn't a convenience wrapper, but
* you can invoke org.freedesktop.DBus.Peer.GetMachineId on any peer
* to get the machine ID on the other end.
return TRUE;
}
+ _dbus_message_set_timeout_ms(message, timeout_milliseconds);
pending = _dbus_pending_call_new_unlocked (connection,
timeout_milliseconds,
reply_handler_timeout);
_dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, NULL);
_dbus_return_val_if_error_is_set (error, NULL);
+ if (_dbus_transport_can_send_sync_call (connection->transport))
+ {
+ dbus_int32_t serial;
+
+ /* set serial */
+ serial = dbus_message_get_serial (message);
+ if (serial == 0)
+ {
+ serial = _dbus_connection_get_next_client_serial (connection);
+ dbus_message_set_serial (message, serial);
+ }
+
+ reply = _dbus_transport_send_sync_call (connection->transport, message);
+ goto out;
+ }
+
#ifdef HAVE_UNIX_FD_PASSING
CONNECTION_LOCK (connection);
/* call_complete_and_unlock() called from pending_call_block() should
* always fill this in.
*/
+
+out:
_dbus_assert (reply != NULL);
- if (dbus_set_error_from_message (error, reply))
+ if (dbus_set_error_from_message (error, reply))
{
dbus_message_unref (reply);
return NULL;
"_dbus_connection_putback_message_link_unlocked");
}
+dbus_bool_t
+_dbus_connection_putback_message (DBusConnection *connection,
+ DBusMessage *after_message,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusDispatchStatus status;
+ DBusList *message_link = _dbus_list_alloc_link (message);
+ DBusList *after_link;
+ if (message_link == NULL)
+ {
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+ dbus_message_ref (message);
+
+ CONNECTION_LOCK (connection);
+ _dbus_connection_acquire_dispatch (connection);
+ HAVE_LOCK_CHECK (connection);
+
+ after_link = _dbus_list_find_first(&connection->incoming_messages, after_message);
+ _dbus_list_insert_after_link (&connection->incoming_messages, after_link, message_link);
+ connection->n_incoming += 1;
+
+ _dbus_verbose ("Message %p (%s %s %s '%s') put back into queue %p, %d incoming\n",
+ message_link->data,
+ dbus_message_type_to_string (dbus_message_get_type (message_link->data)),
+ dbus_message_get_interface (message_link->data) ?
+ dbus_message_get_interface (message_link->data) :
+ "no interface",
+ dbus_message_get_member (message_link->data) ?
+ dbus_message_get_member (message_link->data) :
+ "no member",
+ dbus_message_get_signature (message_link->data),
+ connection, connection->n_incoming);
+
+ _dbus_message_trace_ref (message_link->data, -1, -1,
+ "_dbus_connection_putback_message");
+
+ _dbus_connection_release_dispatch (connection);
+
+ status = _dbus_connection_get_dispatch_status_unlocked (connection);
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
+
+ return TRUE;
+}
+
+dbus_bool_t
+_dbus_connection_remove_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ DBusDispatchStatus status;
+ dbus_bool_t removed;
+
+ CONNECTION_LOCK (connection);
+ _dbus_connection_acquire_dispatch (connection);
+ HAVE_LOCK_CHECK (connection);
+
+ removed = _dbus_list_remove(&connection->incoming_messages, message);
+
+ if (removed)
+ {
+ connection->n_incoming -= 1;
+ dbus_message_unref(message);
+ _dbus_verbose ("Message %p removed from incoming queue\n", message);
+ }
+ else
+ _dbus_verbose ("Message %p not found in the incoming queue\n", message);
+
+ _dbus_connection_release_dispatch (connection);
+
+ status = _dbus_connection_get_dispatch_status_unlocked (connection);
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
+ return removed;
+}
+
/**
* Returns the first-received message from the incoming message queue,
* removing it from the queue. The caller owns a reference to the
_dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection)
{
HAVE_LOCK_CHECK (connection);
-
- if (connection->n_incoming > 0)
+ if (connection->dispatch_disabled)
+ return DBUS_DISPATCH_COMPLETE;
+ else if (connection->n_incoming > 0)
return DBUS_DISPATCH_DATA_REMAINS;
else if (!_dbus_transport_queue_messages (connection->transport))
return DBUS_DISPATCH_NEED_MEMORY;
else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
{
dbus_error_free (&error);
+ _dbus_string_free (&uuid);
goto out;
}
else
{
ret = dbus_message_new_error (message, error.name, error.message);
dbus_error_free (&error);
+ _dbus_string_free (&uuid);
if (ret == NULL)
goto out;
CONNECTION_LOCK (connection);
+ if (result == DBUS_HANDLER_RESULT_LATER)
+ goto out;
if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
{
_dbus_verbose ("No memory\n");
connection);
out:
- if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
+ if (result == DBUS_HANDLER_RESULT_LATER ||
+ result == DBUS_HANDLER_RESULT_NEED_MEMORY)
{
- _dbus_verbose ("out of memory\n");
+ if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
+ _dbus_verbose ("out of memory\n");
/* Put message back, and we'll start over.
* Yes this means handlers must be idempotent if they
return retval;
}
+/**
+ *
+ * Getter for number of messages in incoming queue.
+ * Useful for sending reply to self (see kdbus_do_iteration)
+ */
+int
+_dbus_connection_get_n_incoming (DBusConnection *connection)
+{
+ return connection->n_incoming;
+}
+
+dbus_bool_t
+_dbus_connection_is_overflowed (DBusConnection *connection)
+{
+ return _dbus_transport_get_overflowed (connection->transport);
+}
/**
* Gets the UNIX user ID of the connection if known. Returns #TRUE if