static void
socket_disconnect (DBusServer *server)
{
  DBusServerSocket *socket_server = (DBusServerSocket*) server;
  int i;

  HAVE_LOCK_CHECK (server);

  for (i = 0 ; i < socket_server->n_fds ; i++)
    {
      if (socket_server->watch[i])
        {
          _dbus_server_remove_watch (server,
                                     socket_server->watch[i]);
          _dbus_watch_unref (socket_server->watch[i]);
          socket_server->watch[i] = NULL;
        }

      _dbus_close_socket (socket_server->fds[i], NULL);
      socket_server->fds[i] = -1;
    }

  if (socket_server->socket_name != NULL)
    {
      DBusString tmp;
      _dbus_string_init_const (&tmp, socket_server->socket_name);
      _dbus_delete_file (&tmp, NULL);
    }

  if (server->published_address)
      _dbus_daemon_unpublish_session_bus_address();

  HAVE_LOCK_CHECK (server);
}
/**
 * Like dbus_server_unref() but does not acquire the lock (must already be held)
 *
 * @param server the server.
 */
void
_dbus_server_unref_unlocked (DBusServer *server)
{
    dbus_int32_t old_refcount;

    /* Keep this in sync with dbus_server_unref */

    _dbus_assert (server != NULL);

    HAVE_LOCK_CHECK (server);

    old_refcount = _dbus_atomic_dec (&server->refcount);
    _dbus_assert (old_refcount > 0);

    _dbus_server_trace_ref (server, old_refcount, old_refcount - 1,
                            "unref_unlocked");

    if (old_refcount == 1)
    {
        _dbus_assert (server->disconnected);

        SERVER_UNLOCK (server);

        _dbus_assert (server->vtable->finalize != NULL);

        (* server->vtable->finalize) (server);
    }
}
/**
 * Like dbus_server_unref() but does not acquire the lock (must already be held)
 *
 * @param server the server.
 */
void
_dbus_server_unref_unlocked (DBusServer *server)
{
  dbus_bool_t last_unref;

  /* Keep this in sync with dbus_server_unref */
  
  _dbus_assert (server != NULL);
  _dbus_assert (server->refcount.value > 0);

  HAVE_LOCK_CHECK (server);
  
#ifdef DBUS_HAVE_ATOMIC_INT
  last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
#else
  _dbus_assert (server->refcount.value > 0);

  server->refcount.value -= 1;
  last_unref = (server->refcount.value == 0);
#endif
  
  if (last_unref)
    {
      _dbus_assert (server->disconnected);
      
      SERVER_UNLOCK (server);
      
      _dbus_assert (server->vtable->finalize != NULL);
      
      (* server->vtable->finalize) (server);
    }
}
/**
 * Adds a watch for this server, chaining out to application-provided
 * watch handlers.
 *
 * @param server the server.
 * @param watch the watch to add.
 */
dbus_bool_t
_dbus_server_add_watch (DBusServer *server,
                        DBusWatch  *watch)
{
    HAVE_LOCK_CHECK (server);
    return protected_change_watch (server, watch,
                                   _dbus_watch_list_add_watch,
                                   NULL, NULL, FALSE);
}
/**
 * Removes a watch previously added with _dbus_server_remove_watch().
 *
 * @param server the server.
 * @param watch the watch to remove.
 */
void
_dbus_server_remove_watch  (DBusServer *server,
                            DBusWatch  *watch)
{
    HAVE_LOCK_CHECK (server);
    protected_change_watch (server, watch,
                            NULL,
                            _dbus_watch_list_remove_watch,
                            NULL, FALSE);
}
/**
 * Like dbus_server_ref() but does not acquire the lock (must already be held)
 *
 * @param server the server.
 */
void
_dbus_server_ref_unlocked (DBusServer *server)
{
    dbus_int32_t old_refcount;

    _dbus_assert (server != NULL);
    HAVE_LOCK_CHECK (server);

    old_refcount = _dbus_atomic_inc (&server->refcount);
    _dbus_assert (old_refcount > 0);
    _dbus_server_trace_ref (server, old_refcount, old_refcount + 1,
                            "ref_unlocked");
}
/**
 * Toggles a watch and notifies app via server's
 * DBusWatchToggledFunction if available. It's an error to call this
 * function on a watch that was not previously added.
 *
 * @param server the server.
 * @param watch the watch to toggle.
 * @param enabled whether to enable or disable
 */
void
_dbus_server_toggle_watch (DBusServer  *server,
                           DBusWatch   *watch,
                           dbus_bool_t  enabled)
{
  _dbus_assert (watch != NULL);

  HAVE_LOCK_CHECK (server);
  protected_change_watch (server, watch,
                          NULL, NULL,
                          _dbus_watch_list_toggle_watch,
                          enabled);
}
/**
 * Like dbus_server_ref() but does not acquire the lock (must already be held)
 *
 * @param server the server.
 */
void
_dbus_server_ref_unlocked (DBusServer *server)
{
  _dbus_assert (server != NULL);
  _dbus_assert (server->refcount.value > 0);
  
  HAVE_LOCK_CHECK (server);

#ifdef DBUS_HAVE_ATOMIC_INT
  _dbus_atomic_inc (&server->refcount);
#else
  _dbus_assert (server->refcount.value > 0);

  server->refcount.value += 1;
#endif
}
static dbus_bool_t
protected_change_watch (DBusServer             *server,
                        DBusWatch              *watch,
                        DBusWatchAddFunction    add_function,
                        DBusWatchRemoveFunction remove_function,
                        DBusWatchToggleFunction toggle_function,
                        dbus_bool_t             enabled)
{
    DBusWatchList *watches;
    dbus_bool_t retval;

    HAVE_LOCK_CHECK (server);

    /* This isn't really safe or reasonable; a better pattern is the "do
     * everything, then drop lock and call out" one; but it has to be
     * propagated up through all callers
     */

    watches = server->watches;
    if (watches)
    {
        server->watches = NULL;
        _dbus_server_ref_unlocked (server);
        SERVER_UNLOCK (server);

        if (add_function)
            retval = (* add_function) (watches, watch);
        else if (remove_function)
        {
            retval = TRUE;
            (* remove_function) (watches, watch);
        }
        else
        {
            retval = TRUE;
            (* toggle_function) (watches, watch, enabled);
        }

        SERVER_LOCK (server);
        server->watches = watches;
        _dbus_server_unref_unlocked (server);

        return retval;
    }
    else
        return FALSE;
}
Exemple #10
0
static dbus_bool_t
protected_change_timeout (DBusServer               *server,
                          DBusTimeout              *timeout,
                          DBusTimeoutAddFunction    add_function,
                          DBusTimeoutRemoveFunction remove_function,
                          DBusTimeoutToggleFunction toggle_function,
                          dbus_bool_t               enabled)
{
    DBusTimeoutList *timeouts;
    dbus_bool_t retval;

    HAVE_LOCK_CHECK (server);

    /* This isn't really safe or reasonable; a better pattern is the "do everything, then
     * drop lock and call out" one; but it has to be propagated up through all callers
     */

    timeouts = server->timeouts;
    if (timeouts)
    {
        server->timeouts = NULL;
        _dbus_server_ref_unlocked (server);
        SERVER_UNLOCK (server);

        if (add_function)
            retval = (* add_function) (timeouts, timeout);
        else if (remove_function)
        {
            retval = TRUE;
            (* remove_function) (timeouts, timeout);
        }
        else
        {
            retval = TRUE;
            (* toggle_function) (timeouts, timeout, enabled);
        }

        SERVER_LOCK (server);
        server->timeouts = timeouts;
        _dbus_server_unref_unlocked (server);

        return retval;
    }
    else
        return FALSE;
}
/* Return value is just for memory, not other failures. */
static dbus_bool_t
handle_new_client_fd_and_unlock (DBusServer *server,
                                 int         client_fd)
{
  DBusConnection *connection;
  DBusTransport *transport;
  DBusNewConnectionFunction new_connection_function;
  DBusServerSocket* socket_server;
  void *new_connection_data;

  socket_server = (DBusServerSocket*)server;
  _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);

  HAVE_LOCK_CHECK (server);

  if (!_dbus_set_fd_nonblocking (client_fd, NULL))
    {
      SERVER_UNLOCK (server);
      return TRUE;
    }

  transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, FALSE);
  if (transport == NULL)
    {
      _dbus_close_socket (client_fd, NULL);
      SERVER_UNLOCK (server);
      return FALSE;
    }

  if (!_dbus_transport_set_auth_mechanisms (transport,
                                            (const char **) server->auth_mechanisms))
    {
      _dbus_transport_unref (transport);
      SERVER_UNLOCK (server);
      return FALSE;
    }

  /* note that client_fd is now owned by the transport, and will be
   * closed on transport disconnection/finalization
   */

  connection = _dbus_connection_new_for_transport (transport);
  _dbus_transport_unref (transport);
  transport = NULL; /* now under the connection lock */

  if (connection == NULL)
    {
      SERVER_UNLOCK (server);
      return FALSE;
    }

  /* See if someone wants to handle this new connection, self-referencing
   * for paranoia.
   */
  new_connection_function = server->new_connection_function;
  new_connection_data = server->new_connection_data;

  _dbus_server_ref_unlocked (server);
  SERVER_UNLOCK (server);

  if (new_connection_function)
    {
      (* new_connection_function) (server, connection,
                                   new_connection_data);
    }
  dbus_server_unref (server);

  /* If no one grabbed a reference, the connection will die. */
  _dbus_connection_close_if_only_one_ref (connection);
  dbus_connection_unref (connection);

  return TRUE;
}