Logo Search packages:      
Sourcecode: dbus version File versions

DBusDispatchStatus dbus_connection_dispatch ( DBusConnection connection  ) 

Processes data buffered while handling watches, queueing zero or more incoming messages. Then pops the first-received message from the current incoming message queue, runs any handlers for it, and unrefs the message. Returns a status indicating whether messages/data remain, more memory is needed, or all data has been processed.

Even if the dispatch status is DBUS_DISPATCH_DATA_REMAINS, does not necessarily dispatch a message, as the data may be part of authentication or the like.

Todo:
some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY
Todo:
FIXME what if we call out to application code to handle a message, holding the dispatch lock, and the application code runs the main loop and dispatches again? Probably deadlocks at the moment. Maybe we want a dispatch status of DBUS_DISPATCH_IN_PROGRESS, and then the GSource etc. could handle the situation? Right now our GSource is NO_RECURSE
Parameters:
connection the connection
Returns:
dispatch status

Definition at line 2964 of file dbus-connection.c.

References _dbus_assert_not_reached, _dbus_connection_acquire_dispatch(), _dbus_connection_ref_unlocked(), _dbus_connection_release_dispatch(), _dbus_exit(), _dbus_hash_table_lookup_int(), _dbus_list_clear(), _dbus_list_copy(), _dbus_list_foreach(), _dbus_list_free_link(), _dbus_list_get_first_link(), _dbus_list_get_next_link, _dbus_object_tree_dispatch_and_unlock(), _dbus_pending_call_complete_and_unlock(), _dbus_string_append_printf(), _dbus_string_free(), _dbus_string_get_const_data(), _dbus_string_init(), DBusList::data, dbus_connection_unref(), dbus_message_get_interface(), dbus_message_get_member(), dbus_message_get_reply_serial(), dbus_message_get_signature(), dbus_message_get_type(), dbus_message_is_signal(), dbus_message_new_error(), dbus_message_unref(), dbus_pending_call_unref(), exit_on_disconnect, filter_list, DBusMessageFilter::function, NULL, objects, pending_replies, and DBusMessageFilter::user_data.

{
  DBusMessage *message;
  DBusList *link, *filter_list_copy, *message_link;
  DBusHandlerResult result;
  DBusPendingCall *pending;
  dbus_int32_t reply_serial;
  DBusDispatchStatus status;

  _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE);

  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
  
  CONNECTION_LOCK (connection);
  status = _dbus_connection_get_dispatch_status_unlocked (connection);
  if (status != DBUS_DISPATCH_DATA_REMAINS)
    {
      /* unlocks and calls out to user code */
      _dbus_connection_update_dispatch_status_and_unlock (connection, status);
      return status;
    }
  
  /* We need to ref the connection since the callback could potentially
   * drop the last ref to it
   */
  _dbus_connection_ref_unlocked (connection);

  _dbus_connection_acquire_dispatch (connection);
  HAVE_LOCK_CHECK (connection);

  message_link = _dbus_connection_pop_message_link_unlocked (connection);
  if (message_link == NULL)
    {
      /* another thread dispatched our stuff */

      _dbus_verbose ("another thread dispatched message (during acquire_dispatch above)\n");
      
      _dbus_connection_release_dispatch (connection);

      status = _dbus_connection_get_dispatch_status_unlocked (connection);

      _dbus_connection_update_dispatch_status_and_unlock (connection, status);
      
      dbus_connection_unref (connection);
      
      return status;
    }

  message = message_link->data;

  _dbus_verbose (" dispatching message %p (%d %s %s '%s')\n",
                 message,
                 dbus_message_get_type (message),
                 dbus_message_get_interface (message) ?
                 dbus_message_get_interface (message) :
                 "no interface",
                 dbus_message_get_member (message) ?
                 dbus_message_get_member (message) :
                 "no member",
                 dbus_message_get_signature (message));

  result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  
  /* Pending call handling must be first, because if you do
   * dbus_connection_send_with_reply_and_block() or
   * dbus_pending_call_block() then no handlers/filters will be run on
   * the reply. We want consistent semantics in the case where we
   * dbus_connection_dispatch() the reply.
   */
  
  reply_serial = dbus_message_get_reply_serial (message);
  pending = _dbus_hash_table_lookup_int (connection->pending_replies,
                                         reply_serial);
  if (pending)
    {
      _dbus_verbose ("Dispatching a pending reply\n");
      _dbus_pending_call_complete_and_unlock (pending, message);
      pending = NULL; /* it's probably unref'd */
      
      CONNECTION_LOCK (connection);
      _dbus_verbose ("pending call completed in dispatch\n");
      result = DBUS_HANDLER_RESULT_HANDLED;
      goto out;
    }
  
  if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy))
    {
      _dbus_connection_release_dispatch (connection);
      HAVE_LOCK_CHECK (connection);
      
      _dbus_connection_failed_pop (connection, message_link);

      /* unlocks and calls user code */
      _dbus_connection_update_dispatch_status_and_unlock (connection,
                                                          DBUS_DISPATCH_NEED_MEMORY);

      if (pending)
        dbus_pending_call_unref (pending);
      dbus_connection_unref (connection);
      
      return DBUS_DISPATCH_NEED_MEMORY;
    }
  
  _dbus_list_foreach (&filter_list_copy,
                  (DBusForeachFunction)_dbus_message_filter_ref,
                  NULL);

  /* We're still protected from dispatch() reentrancy here
   * since we acquired the dispatcher
   */
  CONNECTION_UNLOCK (connection);
  
  link = _dbus_list_get_first_link (&filter_list_copy);
  while (link != NULL)
    {
      DBusMessageFilter *filter = link->data;
      DBusList *next = _dbus_list_get_next_link (&filter_list_copy, link);

      _dbus_verbose ("  running filter on message %p\n", message);
      result = (* filter->function) (connection, message, filter->user_data);

      if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
      break;

      link = next;
    }

  _dbus_list_foreach (&filter_list_copy,
                  (DBusForeachFunction)_dbus_message_filter_unref,
                  NULL);
  _dbus_list_clear (&filter_list_copy);
  
  CONNECTION_LOCK (connection);

  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
    {
      _dbus_verbose ("No memory in %s\n", _DBUS_FUNCTION_NAME);
      goto out;
    }
  else if (result == DBUS_HANDLER_RESULT_HANDLED)
    {
      _dbus_verbose ("filter handled message in dispatch\n");
      goto out;
    }

  /* We're still protected from dispatch() reentrancy here
   * since we acquired the dispatcher
   */
  _dbus_verbose ("  running object path dispatch on message %p (%d %s %s '%s')\n",
                 message,
                 dbus_message_get_type (message),
                 dbus_message_get_interface (message) ?
                 dbus_message_get_interface (message) :
                 "no interface",
                 dbus_message_get_member (message) ?
                 dbus_message_get_member (message) :
                 "no member",
                 dbus_message_get_signature (message));

  HAVE_LOCK_CHECK (connection);
  result = _dbus_object_tree_dispatch_and_unlock (connection->objects,
                                                  message);
  
  CONNECTION_LOCK (connection);

  if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
    {
      _dbus_verbose ("object tree handled message in dispatch\n");
      goto out;
    }

  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
    {
      DBusMessage *reply;
      DBusString str;
      DBusPreallocatedSend *preallocated;

      _dbus_verbose ("  sending error %s\n",
                     DBUS_ERROR_UNKNOWN_METHOD);
      
      if (!_dbus_string_init (&str))
        {
          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
          _dbus_verbose ("no memory for error string in dispatch\n");
          goto out;
        }
              
      if (!_dbus_string_append_printf (&str,
                                       "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n",
                                       dbus_message_get_member (message),
                                       dbus_message_get_signature (message),
                                       dbus_message_get_interface (message)))
        {
          _dbus_string_free (&str);
          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
          _dbus_verbose ("no memory for error string in dispatch\n");
          goto out;
        }
      
      reply = dbus_message_new_error (message,
                                      DBUS_ERROR_UNKNOWN_METHOD,
                                      _dbus_string_get_const_data (&str));
      _dbus_string_free (&str);

      if (reply == NULL)
        {
          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
          _dbus_verbose ("no memory for error reply in dispatch\n");
          goto out;
        }
      
      preallocated = _dbus_connection_preallocate_send_unlocked (connection);

      if (preallocated == NULL)
        {
          dbus_message_unref (reply);
          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
          _dbus_verbose ("no memory for error send in dispatch\n");
          goto out;
        }

      _dbus_connection_send_preallocated_unlocked_no_update (connection, preallocated,
                                                             reply, NULL);

      dbus_message_unref (reply);
      
      result = DBUS_HANDLER_RESULT_HANDLED;
    }
  
  _dbus_verbose ("  done dispatching %p (%d %s %s '%s') on connection %p\n", message,
                 dbus_message_get_type (message),
                 dbus_message_get_interface (message) ?
                 dbus_message_get_interface (message) :
                 "no interface",
                 dbus_message_get_member (message) ?
                 dbus_message_get_member (message) :
                 "no member",
                 dbus_message_get_signature (message),
                 connection);
  
 out:
  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
    {
      _dbus_verbose ("out of memory in %s\n", _DBUS_FUNCTION_NAME);
      
      /* Put message back, and we'll start over.
       * Yes this means handlers must be idempotent if they
       * don't return HANDLED; c'est la vie.
       */
      _dbus_connection_putback_message_link_unlocked (connection,
                                                      message_link);
    }
  else
    {
      _dbus_verbose (" ... done dispatching in %s\n", _DBUS_FUNCTION_NAME);
      
      if (connection->exit_on_disconnect &&
          dbus_message_is_signal (message,
                                  DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
                                  "Disconnected"))
        {
          _dbus_verbose ("Exiting on Disconnected signal\n");
          CONNECTION_UNLOCK (connection);
          _dbus_exit (1);
          _dbus_assert_not_reached ("Call to exit() returned");
        }
      
      _dbus_list_free_link (message_link);
      dbus_message_unref (message); /* don't want the message to count in max message limits
                                     * in computing dispatch status below
                                     */
    }
  
  _dbus_connection_release_dispatch (connection);
  HAVE_LOCK_CHECK (connection);

  _dbus_verbose ("%s before final status update\n", _DBUS_FUNCTION_NAME);
  status = _dbus_connection_get_dispatch_status_unlocked (connection);

  /* unlocks and calls user code */
  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
  
  dbus_connection_unref (connection);
  
  return status;
}


Generated by  Doxygen 1.6.0   Back to index