static void
do_io_error (DBusTransport *transport)
{
  _dbus_transport_ref (transport);
  _dbus_transport_disconnect (transport);
  _dbus_transport_unref (transport);
}
Beispiel #2
0
/**
 * Handles a watch by reading data, writing data, or disconnecting
 * the transport, as appropriate for the given condition.
 *
 * @param transport the transport.
 * @param watch the watch.
 * @param condition the current state of the watched file descriptor.
 * @returns #FALSE if not enough memory to fully handle the watch
 */
dbus_bool_t
_dbus_transport_handle_watch (DBusTransport           *transport,
                              DBusWatch               *watch,
                              unsigned int             condition)
{
  dbus_bool_t retval;
  
  _dbus_assert (transport->vtable->handle_watch != NULL);

  if (transport->disconnected)
    return TRUE;

  if (dbus_watch_get_socket (watch) < 0)
    {
      _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
      return TRUE;
    }
  
  _dbus_watch_sanitize_condition (watch, &condition);

  _dbus_transport_ref (transport);
  _dbus_watch_ref (watch);
  retval = (* transport->vtable->handle_watch) (transport, watch, condition);
  _dbus_watch_unref (watch);
  _dbus_transport_unref (transport);

  return retval;
}
static void
check_read_watch (DBusTransport *transport)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
  dbus_bool_t need_read_watch;

  _dbus_verbose ("fd = %" DBUS_SOCKET_FORMAT "\n",
                 _dbus_socket_printable (socket_transport->fd));
  
  if (transport->connection == NULL)
    return;

  if (transport->disconnected)
    {
      _dbus_assert (socket_transport->read_watch == NULL);
      return;
    }
  
  _dbus_transport_ref (transport);

  if (_dbus_transport_try_to_authenticate (transport))
    need_read_watch =
      (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
      (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
  else
    {
      if (transport->receive_credentials_pending)
        need_read_watch = TRUE;
      else
        {
          /* The reason to disable need_read_watch when not WAITING_FOR_INPUT
           * is to avoid spinning on the file descriptor when we're waiting
           * to write or for some other part of the auth process
           */
          DBusAuthState auth_state;
          
          auth_state = _dbus_auth_do_work (transport->auth);

          /* If we need memory we install the read watch just in case,
           * if there's no need for it, it will get de-installed
           * next time we try reading. If we're authenticated we
           * install it since we normally have it installed while
           * authenticated.
           */
          if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT ||
              auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY ||
              auth_state == DBUS_AUTH_STATE_AUTHENTICATED)
            need_read_watch = TRUE;
          else
            need_read_watch = FALSE;
        }
    }

  _dbus_verbose ("  setting read watch enabled = %d\n", need_read_watch);
  _dbus_connection_toggle_watch_unlocked (transport->connection,
                                          socket_transport->read_watch,
                                          need_read_watch);

  _dbus_transport_unref (transport);
}
Beispiel #4
0
static void
live_messages_notify (DBusCounter *counter,
                           void        *user_data)
{
  DBusTransport *transport = user_data;

  _dbus_transport_ref (transport);

#if 0
  _dbus_verbose ("Size counter value is now %d\n",
                 (int) _dbus_counter_get_size_value (counter));
  _dbus_verbose ("Unix FD counter value is now %d\n",
                 (int) _dbus_counter_get_unix_fd_value (counter));
#endif

  /* disable or re-enable the read watch for the transport if
   * required.
   */
  if (transport->vtable->live_messages_changed)
    {
      _dbus_connection_lock (transport->connection);
      (* transport->vtable->live_messages_changed) (transport);
      _dbus_connection_unlock (transport->connection);
    }

  _dbus_transport_unref (transport);
}
static void
check_write_watch (DBusTransport *transport)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
  dbus_bool_t needed;

  if (transport->connection == NULL)
    return;

  if (transport->disconnected)
    {
      _dbus_assert (socket_transport->write_watch == NULL);
      return;
    }
  
  _dbus_transport_ref (transport);

  if (_dbus_transport_try_to_authenticate (transport))
    needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
  else
    {
      if (transport->send_credentials_pending)
        needed = TRUE;
      else
        {
          DBusAuthState auth_state;
          
          auth_state = _dbus_auth_do_work (transport->auth);
          
          /* If we need memory we install the write watch just in case,
           * if there's no need for it, it will get de-installed
           * next time we try reading.
           */
          if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND ||
              auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
            needed = TRUE;
          else
            needed = FALSE;
        }
    }

  _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %" DBUS_SOCKET_FORMAT " outgoing messages exist %d\n",
                 needed, transport->connection, socket_transport->write_watch,
                 _dbus_socket_printable (socket_transport->fd),
                 _dbus_connection_has_messages_to_send_unlocked (transport->connection));

  _dbus_connection_toggle_watch_unlocked (transport->connection,
                                          socket_transport->write_watch,
                                          needed);

  _dbus_transport_unref (transport);
}
Beispiel #6
0
/**
 * Sets the connection using this transport. Allows the transport
 * to add watches to the connection, queue incoming messages,
 * and pull outgoing messages.
 *
 * @param transport the transport.
 * @param connection the connection.
 * @returns #FALSE if not enough memory
 */
dbus_bool_t
_dbus_transport_set_connection (DBusTransport  *transport,
                                DBusConnection *connection)
{
  _dbus_assert (transport->vtable->connection_set != NULL);
  _dbus_assert (transport->connection == NULL);
  
  transport->connection = connection;

  _dbus_transport_ref (transport);
  if (!(* transport->vtable->connection_set) (transport))
    transport->connection = NULL;
  _dbus_transport_unref (transport);

  return transport->connection != NULL;
}
Beispiel #7
0
/**
 * Get the socket file descriptor, if any.
 *
 * @param transport the transport
 * @param fd_p pointer to fill in with the descriptor
 * @returns #TRUE if a descriptor was available
 */
dbus_bool_t
_dbus_transport_get_socket_fd (DBusTransport *transport,
                               int           *fd_p)
{
  dbus_bool_t retval;
  
  if (transport->vtable->get_socket_fd == NULL)
    return FALSE;

  if (transport->disconnected)
    return FALSE;

  _dbus_transport_ref (transport);

  retval = (* transport->vtable->get_socket_fd) (transport,
                                                 fd_p);
  
  _dbus_transport_unref (transport);

  return retval;
}
Beispiel #8
0
/**
 * Performs a single poll()/select() on the transport's file
 * descriptors and then reads/writes data as appropriate,
 * queueing incoming messages and sending outgoing messages.
 * This is the backend for _dbus_connection_do_iteration().
 * See _dbus_connection_do_iteration() for full details.
 *
 * @param transport the transport.
 * @param flags indicates whether to read or write, and whether to block.
 * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
 */
void
_dbus_transport_do_iteration (DBusTransport  *transport,
                              unsigned int    flags,
                              int             timeout_milliseconds)
{
  _dbus_assert (transport->vtable->do_iteration != NULL);

  _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
                 flags, timeout_milliseconds, !transport->disconnected);
  
  if ((flags & (DBUS_ITERATION_DO_WRITING |
                DBUS_ITERATION_DO_READING)) == 0)
    return; /* Nothing to do */

  if (transport->disconnected)
    return;

  _dbus_transport_ref (transport);
  (* transport->vtable->do_iteration) (transport, flags,
                                       timeout_milliseconds);
  _dbus_transport_unref (transport);

  _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
}
static dbus_bool_t
do_authentication (DBusTransport *transport,
                   dbus_bool_t    do_reading,
                   dbus_bool_t    do_writing,
		   dbus_bool_t   *auth_completed)
{
  dbus_bool_t oom;
  dbus_bool_t orig_auth_state;

  oom = FALSE;
  
  orig_auth_state = _dbus_transport_try_to_authenticate (transport);

  /* This is essential to avoid the check_write_watch() at the end,
   * we don't want to add a write watch in do_iteration before
   * we try writing and get EAGAIN
   */
  if (orig_auth_state)
    {
      if (auth_completed)
        *auth_completed = FALSE;
      return TRUE;
    }
  
  _dbus_transport_ref (transport);
  
  while (!_dbus_transport_try_to_authenticate (transport) &&
         _dbus_transport_get_is_connected (transport))
    {      
      if (!exchange_credentials (transport, do_reading, do_writing))
        {
          /* OOM */
          oom = TRUE;
          goto out;
        }
      
      if (transport->send_credentials_pending ||
          transport->receive_credentials_pending)
        {
          _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n",
                         transport->send_credentials_pending,
                         transport->receive_credentials_pending);
          goto out;
        }

#define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client")
      switch (_dbus_auth_do_work (transport->auth))
        {
        case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
          _dbus_verbose (" %s auth state: waiting for input\n",
                         TRANSPORT_SIDE (transport));
          if (!do_reading || !read_data_into_auth (transport, &oom))
            goto out;
          break;
      
        case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
          _dbus_verbose (" %s auth state: waiting for memory\n",
                         TRANSPORT_SIDE (transport));
          oom = TRUE;
          goto out;
          break;
      
        case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
          _dbus_verbose (" %s auth state: bytes to send\n",
                         TRANSPORT_SIDE (transport));
          if (!do_writing || !write_data_from_auth (transport))
            goto out;
          break;
      
        case DBUS_AUTH_STATE_NEED_DISCONNECT:
          _dbus_verbose (" %s auth state: need to disconnect\n",
                         TRANSPORT_SIDE (transport));
          do_io_error (transport);
          break;
      
        case DBUS_AUTH_STATE_AUTHENTICATED:
          _dbus_verbose (" %s auth state: authenticated\n",
                         TRANSPORT_SIDE (transport));
          break;
        }
    }

 out:
  if (auth_completed)
    *auth_completed = (orig_auth_state != _dbus_transport_try_to_authenticate (transport));
  
  check_read_watch (transport);
  check_write_watch (transport);
  _dbus_transport_unref (transport);

  if (oom)
    return FALSE;
  else
    return TRUE;
}
/* 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;
}
/**
 * Creates the client-side transport for
 * a debug-pipe connection connected to the
 * given debug-pipe server name.
 *
 * @param server_name name of server to connect to
 * @param error address where an error can be returned.
 * @returns #NULL on no memory or transport
 */
DBusTransport*
_dbus_transport_debug_pipe_new (const char     *server_name,
                                DBusError      *error)
{
    DBusTransport *client_transport;
    DBusTransport *server_transport;
    DBusConnection *connection;
    int client_fd, server_fd;
    DBusServer *server;
    DBusString address;

    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    if (server_pipe_hash == NULL)
    {
        dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
        return NULL;
    }

    server = _dbus_hash_table_lookup_string (server_pipe_hash,
             server_name);
    if (server == NULL ||
            ((DBusServerDebugPipe*)server)->disconnected)
    {
        dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
        return NULL;
    }

    if (!_dbus_string_init (&address))
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return NULL;
    }

    if (!_dbus_string_append (&address, "debug-pipe:name=") ||
            !_dbus_string_append (&address, server_name))
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        _dbus_string_free (&address);
        return NULL;
    }

    if (!_dbus_full_duplex_pipe (&client_fd, &server_fd, FALSE,
                                 NULL))
    {
        _dbus_verbose ("failed to create full duplex pipe\n");
        dbus_set_error (error, DBUS_ERROR_FAILED, "Could not create full-duplex pipe");
        _dbus_string_free (&address);
        return NULL;
    }

    _dbus_fd_set_close_on_exec (client_fd);
    _dbus_fd_set_close_on_exec (server_fd);

    client_transport = _dbus_transport_new_for_socket (client_fd,
                       NULL, &address);
    if (client_transport == NULL)
    {
        _dbus_close_socket (client_fd, NULL);
        _dbus_close_socket (server_fd, NULL);
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        _dbus_string_free (&address);
        return NULL;
    }

    _dbus_string_free (&address);

    client_fd = -1;

    server_transport = _dbus_transport_new_for_socket (server_fd,
                       &server->guid_hex, NULL);
    if (server_transport == NULL)
    {
        _dbus_transport_unref (client_transport);
        _dbus_close_socket (server_fd, NULL);
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return NULL;
    }

    server_fd = -1;

    if (!_dbus_transport_set_auth_mechanisms (server_transport,
            (const char**) server->auth_mechanisms))
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        _dbus_transport_unref (server_transport);
        _dbus_transport_unref (client_transport);
        return NULL;
    }

    connection = _dbus_connection_new_for_transport (server_transport);
    _dbus_transport_unref (server_transport);
    server_transport = NULL;

    if (connection == NULL)
    {
        _dbus_transport_unref (client_transport);
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return NULL;
    }

    /* See if someone wants to handle this new connection,
     * self-referencing for paranoia
     */
    if (server->new_connection_function)
    {
        dbus_server_ref (server);
        (* server->new_connection_function) (server, connection,
                                             server->new_connection_data);
        dbus_server_unref (server);
    }

    /* If no one grabbed a reference, the connection will die,
     * and the client transport will get an immediate disconnect
     */
    _dbus_connection_close_if_only_one_ref (connection);
    dbus_connection_unref (connection);

    return client_transport;
}