#include "dbus-transport.h"
#include "dbus-watch.h"
#include "dbus-connection-internal.h"
+#include "dbus-pending-call-internal.h"
#include "dbus-list.h"
#include "dbus-hash.h"
#include "dbus-message-internal.h"
#include "dbus-pending-call.h"
#include "dbus-object-tree.h"
#include "dbus-threads-internal.h"
+#include "dbus-bus.h"
#ifdef DBUS_DISABLE_CHECKS
#define TOOK_LOCK_CHECK(connection)
reply_serial);
if (pending != NULL)
{
- if (pending->timeout_added)
+ if (_dbus_pending_call_is_timeout_added (pending))
_dbus_connection_remove_timeout_unlocked (connection,
- pending->timeout);
+ _dbus_pending_call_get_timeout (pending));
- pending->timeout_added = FALSE;
+ _dbus_pending_call_set_timeout_added (pending, FALSE);
}
}
+
+
connection->n_incoming += 1;
_dbus_connection_wakeup_mainloop (connection);
dbus_message_get_signature (message),
dbus_message_get_reply_serial (message),
connection,
- connection->n_incoming);
-}
+ connection->n_incoming);}
/**
* Adds a link + message to the incoming message queue.
* @todo This needs to wake up the mainloop if it is in
* a poll/select and this is a multithreaded app.
*/
-static void
+void
_dbus_connection_queue_synthesized_message_link (DBusConnection *connection,
DBusList *link)
{
_dbus_connection_attach_pending_call_unlocked (DBusConnection *connection,
DBusPendingCall *pending)
{
+ dbus_uint32_t reply_serial;
+ DBusTimeout *timeout;
+
HAVE_LOCK_CHECK (connection);
-
- _dbus_assert (pending->reply_serial != 0);
- if (!_dbus_connection_add_timeout_unlocked (connection, pending->timeout))
+ reply_serial = _dbus_pending_call_get_reply_serial (pending);
+
+ _dbus_assert (reply_serial != 0);
+
+ timeout = _dbus_pending_call_get_timeout (pending);
+
+ if (!_dbus_connection_add_timeout_unlocked (connection, timeout))
return FALSE;
if (!_dbus_hash_table_insert_int (connection->pending_replies,
- pending->reply_serial,
+ reply_serial,
pending))
{
- _dbus_connection_remove_timeout_unlocked (connection, pending->timeout);
+ _dbus_connection_remove_timeout_unlocked (connection, timeout);
HAVE_LOCK_CHECK (connection);
return FALSE;
}
- pending->timeout_added = TRUE;
- pending->connection = connection;
+ _dbus_pending_call_set_timeout_added (pending, TRUE);
dbus_pending_call_ref (pending);
free_pending_call_on_hash_removal (void *data)
{
DBusPendingCall *pending;
-
+ DBusConnection *connection;
+
if (data == NULL)
return;
pending = data;
- if (pending->connection)
+ connection = _dbus_pending_call_get_connection (pending);
+
+ if (connection)
{
- if (pending->timeout_added)
+ if (_dbus_pending_call_is_timeout_added (pending))
{
- _dbus_connection_remove_timeout_unlocked (pending->connection,
- pending->timeout);
- pending->timeout_added = FALSE;
- }
-
- pending->connection = NULL;
+ _dbus_connection_remove_timeout_unlocked (connection,
+ _dbus_pending_call_get_timeout (pending));
+ _dbus_pending_call_set_timeout_added (pending, FALSE);
+ }
+
dbus_pending_call_unref (pending);
}
}
dbus_pending_call_ref (pending);
_dbus_hash_table_remove_int (connection->pending_replies,
- pending->reply_serial);
- _dbus_assert (pending->connection == NULL);
+ _dbus_pending_call_get_reply_serial (pending));
dbus_pending_call_unref (pending);
}
*/
dbus_pending_call_ref (pending);
_dbus_hash_table_remove_int (connection->pending_replies,
- pending->reply_serial);
- _dbus_assert (pending->connection == NULL);
+ _dbus_pending_call_get_reply_serial (pending));
CONNECTION_UNLOCK (connection);
dbus_pending_call_unref (pending);
}
}
/**
- * Completes a pending call with the given message,
- * or if the message is #NULL, by timing out the pending call.
- *
- * @param pending the pending call
- * @param message the message to complete the call with, or #NULL
- * to time out the call
- */
-void
-_dbus_pending_call_complete_and_unlock (DBusPendingCall *pending,
- DBusMessage *message)
-{
- if (message == NULL)
- {
- message = pending->timeout_link->data;
- _dbus_list_clear (&pending->timeout_link);
- }
- else
- dbus_message_ref (message);
-
- _dbus_verbose (" handing message %p (%s) to pending call serial %u\n",
- message,
- dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
- "method return" :
- dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
- "error" : "other type",
- pending->reply_serial);
-
- _dbus_assert (pending->reply == NULL);
- _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
- pending->reply = message;
-
- dbus_pending_call_ref (pending); /* in case there's no app with a ref held */
- _dbus_connection_detach_pending_call_and_unlock (pending->connection, pending);
-
- /* Must be called unlocked since it invokes app callback */
- _dbus_pending_call_notify (pending);
- dbus_pending_call_unref (pending);
-}
-
-/**
* Acquire the transporter I/O path. This must be done before
* doing any I/O in the transporter. May sleep and drop the
* IO path mutex while waiting for the I/O path.
_dbus_connection_update_dispatch_status_and_unlock (connection, status);
}
-/** Alias for dbus_connection_close(). This method is DEPRECATED and will be
- * removed for 1.0. Change your code to use dbus_connection_close() instead.
- *
- * @param connection the connection.
- * @deprecated
- */
-void
-dbus_connection_disconnect (DBusConnection *connection)
-{
- dbus_connection_close (connection);
-}
-
static dbus_bool_t
_dbus_connection_get_is_connected_unlocked (DBusConnection *connection)
{
DBusDispatchStatus status;
DBusPendingCall *pending = data;
- connection = pending->connection;
+ connection = _dbus_pending_call_get_connection (pending);
CONNECTION_LOCK (connection);
- if (pending->timeout_link)
- {
- _dbus_connection_queue_synthesized_message_link (connection,
- pending->timeout_link);
- pending->timeout_link = NULL;
- }
-
+ _dbus_pending_call_queue_timeout_error (pending,
+ connection);
_dbus_connection_remove_timeout_unlocked (connection,
- pending->timeout);
- pending->timeout_added = FALSE;
+ _dbus_pending_call_get_timeout (pending));
+ _dbus_pending_call_set_timeout_added (pending, FALSE);
_dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME);
status = _dbus_connection_get_dispatch_status_unlocked (connection);
*
* @param connection the connection
* @param message the message to send
- * @param pending_return return location for a #DBusPendingCall object, or #NULL
+ * @param pending_return return location for a #DBusPendingCall object, or #NULLif connection is disconnected
* @param timeout_milliseconds timeout in milliseconds or -1 for default
- * @returns #TRUE if the message is successfully queued, #FALSE if no memory.
+ * @returns #FALSE if no memory, #TRUE otherwise.
*
*/
dbus_bool_t
int timeout_milliseconds)
{
DBusPendingCall *pending;
- DBusMessage *reply;
- DBusList *reply_link;
dbus_int32_t serial = -1;
DBusDispatchStatus status;
if (pending_return)
*pending_return = NULL;
-
+
+ CONNECTION_LOCK (connection);
+
+ if (!_dbus_connection_get_is_connected_unlocked (connection))
+ {
+ CONNECTION_UNLOCK (connection);
+
+ *pending_return = NULL;
+
+ return TRUE;
+ }
+
pending = _dbus_pending_call_new (connection,
timeout_milliseconds,
reply_handler_timeout);
if (pending == NULL)
- return FALSE;
+ {
+ CONNECTION_UNLOCK (connection);
+ return FALSE;
+ }
- CONNECTION_LOCK (connection);
-
/* Assign a serial to the message */
- if (dbus_message_get_serial (message) == 0)
+ serial = dbus_message_get_serial (message);
+ if (serial == 0)
{
serial = _dbus_connection_get_next_client_serial (connection);
_dbus_message_set_serial (message, serial);
}
- pending->reply_serial = serial;
-
- reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
- "No reply within specified time");
- if (reply == NULL)
+ if (!_dbus_pending_call_set_timeout_error (pending, message, serial))
goto error;
-
- reply_link = _dbus_list_alloc_link (reply);
- if (reply_link == NULL)
- {
- CONNECTION_UNLOCK (connection);
- dbus_message_unref (reply);
- goto error_unlocked;
- }
-
- pending->timeout_link = reply_link;
-
+
/* Insert the serial in the pending replies hash;
* hash takes a refcount on DBusPendingCall.
* Also, add the timeout.
return NULL;
}
+static void
+connection_timeout_and_complete_all_pending_calls_unlocked (DBusConnection *connection)
+{
+ DBusHashIter iter;
+
+ _dbus_hash_iter_init (connection->pending_replies, &iter);
+
+ /* create list while we remove the iters from the hash
+ because we need to go over it a couple of times */
+ while (_dbus_hash_iter_next (&iter))
+ {
+ DBusPendingCall *pending;
+
+ pending = (DBusPendingCall *) _dbus_hash_iter_get_value (&iter);
+ dbus_pending_call_ref (pending);
+
+ _dbus_pending_call_queue_timeout_error (pending,
+ connection);
+ _dbus_connection_remove_timeout_unlocked (connection,
+ _dbus_pending_call_get_timeout (pending));
+
+ _dbus_hash_iter_remove_entry (&iter);
+
+ dbus_pending_call_unref (pending);
+ }
+}
+
+static void
+complete_pending_call_and_unlock (DBusPendingCall *pending,
+ DBusMessage *message)
+{
+ _dbus_pending_call_set_reply (pending, message);
+ dbus_pending_call_ref (pending); /* in case there's no app with a ref held */
+ _dbus_connection_detach_pending_call_and_unlock (_dbus_pending_call_get_connection (pending), pending);
+
+ /* Must be called unlocked since it invokes app callback */
+ _dbus_pending_call_complete (pending);
+ dbus_pending_call_unref (pending);
+}
+
static dbus_bool_t
check_for_reply_and_update_dispatch_unlocked (DBusPendingCall *pending)
{
DBusDispatchStatus status;
DBusConnection *connection;
- connection = pending->connection;
+ connection = _dbus_pending_call_get_connection (pending);
- reply = check_for_reply_unlocked (connection, pending->reply_serial);
+ reply = check_for_reply_unlocked (connection,
+ _dbus_pending_call_get_reply_serial (pending));
if (reply != NULL)
{
_dbus_verbose ("%s checked for reply\n", _DBUS_FUNCTION_NAME);
_dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n");
- _dbus_pending_call_complete_and_unlock (pending, reply);
+ complete_pending_call_and_unlock (pending, reply);
dbus_message_unref (reply);
CONNECTION_LOCK (connection);
if (dbus_pending_call_get_completed (pending))
return;
- if (pending->connection == NULL)
+ connection = _dbus_pending_call_get_connection (pending);
+ if (connection == NULL)
return; /* call already detached */
dbus_pending_call_ref (pending); /* necessary because the call could be canceled */
-
- connection = pending->connection;
- client_serial = pending->reply_serial;
+ client_serial = _dbus_pending_call_get_reply_serial (pending);
/* note that timeout_milliseconds is limited to a smallish value
* in _dbus_pending_call_new() so overflows aren't possible
* below
*/
- timeout_milliseconds = dbus_timeout_get_interval (pending->timeout);
+ timeout_milliseconds = dbus_timeout_get_interval (_dbus_pending_call_get_timeout (pending));
/* Flush message queue */
dbus_connection_flush (connection);
* confusing
*/
- _dbus_pending_call_complete_and_unlock (pending, NULL);
+ complete_pending_call_and_unlock (pending, NULL);
dbus_pending_call_unref (pending);
return;
}
_dbus_assert (!dbus_pending_call_get_completed (pending));
/* unlock and call user code */
- _dbus_pending_call_complete_and_unlock (pending, NULL);
+ complete_pending_call_and_unlock (pending, NULL);
/* update user code on dispatch status */
CONNECTION_LOCK (connection);
* @param dispatch dispatch new messages or leave them on the incoming queue
* @returns #TRUE if the disconnect message has not been processed
*/
-dbus_bool_t
+static dbus_bool_t
_dbus_connection_read_write_dispatch (DBusConnection *connection,
int timeout_milliseconds,
dbus_bool_t dispatch)
_DBUS_FUNCTION_NAME);
connection_forget_shared_unlocked (connection);
-
+
+ /* If we have pending calls queued timeouts on disconnect */
+ connection_timeout_and_complete_all_pending_calls_unlocked (connection);
+
/* We haven't sent the disconnect message already,
* and all real messages have been queued up.
*/
if (pending)
{
_dbus_verbose ("Dispatching a pending reply\n");
- _dbus_pending_call_complete_and_unlock (pending, message);
+ complete_pending_call_and_unlock (pending, message);
pending = NULL; /* it's probably unref'd */
CONNECTION_LOCK (connection);
{
_dbus_verbose (" ... done dispatching in %s\n", _DBUS_FUNCTION_NAME);
- if (connection->exit_on_disconnect &&
- dbus_message_is_signal (message,
+ if (dbus_message_is_signal (message,
DBUS_INTERFACE_LOCAL,
"Disconnected"))
{
- _dbus_verbose ("Exiting on Disconnected signal\n");
- CONNECTION_UNLOCK (connection);
- _dbus_exit (1);
- _dbus_assert_not_reached ("Call to exit() returned");
+ _dbus_bus_check_connection_and_unref (connection);
+
+ if (connection->exit_on_disconnect)
+ {
+ CONNECTION_UNLOCK (connection);
+
+ _dbus_verbose ("Exiting on Disconnected signal\n");
+ _dbus_exit (1);
+ _dbus_assert_not_reached ("Call to exit() returned");
+ }
}
_dbus_list_free_link (message_link);